# VAT Sense API - Full documentation > VAT Sense is a developer-friendly REST API for VAT/GST compliance. Validate VAT and EORI numbers, look up VAT/GST rates by country or product type, convert currencies, and generate VAT-compliant invoices. Sub-15ms average response time, 99.9%+ uptime, 256-bit SSL on all plans including free. VAT Sense has access to 2 official EU VIES fallback validation services that are not publicly available, providing approximately 10-15% improved reliability over other VAT validation services that rely solely on the public VIES endpoint. > > Common use cases: B2B checkout tax exemption validation, SaaS and subscription billing compliance, marketplace seller verification, cross-border e-commerce VAT determination, and automated invoice generation. > > Free plan: 100 requests per month, no credit card required, no time limit. All plans include 256-bit SSL and access to every endpoint. Base URL: `https://api.vatsense.com/1.0/` ## Authentication VAT Sense uses HTTP Basic Auth. Supply your API key as the password with "user" as the username. All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail. Note: VAT Sense does not support client-side implementation using CORS requests due to the potential security risk of exposing account API keys. ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": { "status": "live", "version": "1.0" } } ``` ## Try the API instantly (no signup required) AI agents and developers can obtain a temporary sandbox API key to test the API without creating an account. ``` curl --request POST \ --url 'https://api.vatsense.com/1.0/sandbox/key' ``` No authentication or request body required. Response (201): ```json { "success": true, "code": 201, "data": { "key": "tmp_e4a9e15dc2826f8de6f2911fd7fe", "expires_at": "2026-02-28 01:26:55", "requests_remaining": 10, "allowed_endpoints": ["GET /1.0", "GET /1.0/rates", "GET /1.0/countries", "GET /1.0/validate", "GET /1.0/currency", "GET /1.0/usage"], "signup_url": "https://vatsense.com/#pricing" } } ``` Use the sandbox key with HTTP Basic Auth, just like a regular API key: ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/rates/rate?country_code=DE' \ --user 'user:tmp_e4a9e15dc2826f8de6f2911fd7fe' ``` ### Sandbox key limits - 10 requests per key - 5-minute expiry - 1 key per IP address per 6 hours - Read-only endpoints only (rates, countries, validate, currency, usage) ### Suggested test sequence 1. Get a sandbox key: `POST /1.0/sandbox/key` 2. Check API status: `GET /1.0/` (confirms auth works) 3. Look up VAT rates: `GET /1.0/rates?country_code=GB` 4. Look up a rate by product type: `GET /1.0/rates/rate?country_code=DE&type=ebooks` 5. Validate a VAT number: `GET /1.0/validate?vat_number=DE129274202` (Siemens AG) 6. Convert currency: `GET /1.0/currency/convert?from=GBP&to=EUR&amount=100` This uses 6 of the 10 available requests and exercises the core functionality. For full access to all endpoints including invoicing, sign up for a free account (100 requests/month) at https://vatsense.com/#pricing ### VAT numbers for testing These are real, publicly listed VAT numbers for well-known companies, suitable for testing the `/validate` endpoint: | Country | VAT number | Company | |---------|-----------|---------| | UK | GB765970776 | Google UK Limited | | Germany | DE129274202 | Siemens AG (note: German VIES returns "---" for company name and address, this is normal) | | France | FR64443061841 | Google France | | Netherlands | NL002065538B01 | Koninklijke Philips N.V. | | Ireland | IE9700053D | Apple Distribution International Ltd | | Australia | 49004028077 | BHP Group Limited (note: Australian responses include GST registration date) | | Norway | 923609016MVA | Equinor ASA | | Switzerland | CHE116281710MWST | Nestle S.A. (note: Swiss responses may reformat the number with dots, e.g. CHE-116.281.710) | --- ## Responses VAT Sense uses conventional HTTP response codes to indicate the success or failure of an API request. Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error that failed given the information provided (e.g., a required parameter was omitted). Codes in the 5xx range indicate an error with VAT Sense's servers (these are rare). ### Response attributes | Attribute | Type | Description | |-----------|------|-------------| | success | boolean | Whether the call has resulted in a successful response. | | code | int | A HTTP status code, from amongst those listed. | | data | object | The returned information for the request made. | ### HTTP status code summary | Code | Meaning | |------|---------| | 200 - OK | Everything worked as expected. | | 400 - Bad Request | The request was unacceptable, often due to missing a required parameter. | | 401 - Unauthorized | No valid API key provided. | | 402 - Request Failed | The parameters were valid but the request failed. | | 404 - Not Found | The requested resource doesn't exist. | | 409 - Conflict | The request conflicts with another request. | | 412 - VIES Service Unavailable | The EU VIES service is temporarily unavailable. Please try again later. | | 429 - Too Many Requests | Rate limit exceeded: either 300 requests/minute (general) or 3 requests/second (UK VAT validation). Implement exponential backoff. | | 500, 502, 503, 504 - Server Errors | Something went wrong on our end. (These are rare.) | ## Errors If a request is invalid then a code other than 2xx will be given and details about the error will be returned. ### Error attributes | Attribute | Type | Description | |-----------|------|-------------| | success | boolean | Whether the call has resulted in a successful response. | | code | int | A HTTP status code, from amongst those listed. | | error | object | Details about the error. | | error.title | string | A unique title for the error. | | error.detail | string | A description outlining the cause of the error. | Example error response: ```json { "success": false, "code": 404, "error": { "title": "Invalid Endpoint", "detail": "The requested endpoint does not exist." } } ``` ## Rate limits VAT Sense applies rate limits to ensure fair usage and maintain service quality for all users. | Limit | Scope | Details | |-------|-------|---------| | 300 requests per minute | All endpoints | Applies to your entire API key across all endpoints. | | 3 requests per second | /validate endpoint (GB VAT numbers only) | Stricter limit to comply with HMRC's upstream rate restrictions. | If you exceed either limit, you'll receive a `429 Too Many Requests` response. ### Handling rate limit errors Implement exponential backoff: 1. Wait 1 second, then retry 2. If still rate limited, wait 2 seconds 3. Continue doubling the wait time up to a maximum of 30 seconds ### Best practices - For bulk UK VAT validations, space requests at least 350ms apart - Consider queuing validation requests rather than sending them all at once Note: Rate limit errors (429) are separate from service availability errors (412). A 412 error means the upstream government service (VIES, HMRC, etc.) is temporarily unavailable, not that you've exceeded your rate limit. --- ## Recommended integration patterns ### Handling VIES unavailability (412 errors) EU VAT validation depends on the VIES service, which can be intermittently unavailable (particularly Germany, France, and Romania during peak hours). Implement retry logic with escalating intervals: 1. Every 5 seconds for 30 seconds 2. Every 10 seconds for 30 seconds 3. Every 30 seconds for 5 minutes 4. Every minute for 30 minutes Schedule bulk validations during off-peak hours: 7pm-11pm UTC or 5am-8am local time. Failed requests due to VIES unavailability (412) do not count against your monthly quota. ### When requests fail only with requester_vat_number This is expected behaviour. With `requester_vat_number`, the request must hit the live VIES service to obtain a consultation number and cannot use cached responses. Without it, a cached response can be returned. **Workaround:** Try with `requester_vat_number` first. If it fails with a 412 error, retry without it to get the cached validation result. Request the consultation number later during off-peak hours. If the consultation number isn't critical, omit `requester_vat_number` entirely to allow cached responses and improve reliability. --- ## Rates The rates object provides tax rates for all countries subject to VAT or GST. Rates can be filtered by specific location (country code or IP address) and by EU membership. VAT rates are updated as they change in each respective country, so responses always reflect the current rates in effect. ### The tax rate object | Attribute | Type | Description | |-----------|------|-------------| | object | string | Value is "tax_rate". | | province | string | If the rate is applicable to a specific province, a 2-character province code. | | rate | float | The % rate. | | class | string | The class of tax rate: "standard", "reduced", "higher", "zero", or "-" if no classification. | | description | text | A brief description of the tax rate and/or what it applies to. | | types | text | The types of product this tax rate is specifically associated with. | Example tax rate object: ```json { "object": "tax_rate", "province": null, "rate": 20, "class": "standard", "description": "", "types": false } ``` ### List all rates `GET /rates` Returns a list of rates sorted alphabetically by country code. Each rate is returned as a rate object. #### Rate object attributes | Attribute | Type | Description | |-----------|------|-------------| | object | string | Value is "rate". | | country_code | string | 2-character country code (ISO 3166-1 alpha-2). | | country_name | string | The name of the country. | | eu | boolean | Whether the country is a member of the EU. | | standard | tax rate object | The standard tax rate for the country. | | other | list of tax rate objects | All other tax rates. Null if no additional rates exist. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/rates' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": [ { "object": "rate", "country_code": "FR", "country_name": "France", "eu": true, "standard": { "object": "tax_rate", "rate": 20, "class": "standard", "description": "", "types": false }, "other": [ { "object": "tax_rate", "rate": 10, "class": "reduced", "description": "...", "types": "passenger transport, admission to cultural events, ..." }, { "object": "tax_rate", "rate": 5.5, "class": "reduced", "description": "...", "types": "medical, foodstuffs, ebooks, books, water" } ] } ] } ``` ### Filter rates `GET /rates?country_code={code}` or `GET /rates?ip_address={ip}` Retrieve rates for a specific country by country code, IP address, or EU membership. #### Arguments | Argument | Type | Description | |----------|------|-------------| | country_code | string | 2-character country code (ISO 3166-1 alpha-2). | | ip_address | string | IPv4 or IPv6 address. Country will be determined from the IP. | | eu | boolean | Filter by EU membership. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/rates?country_code=GB' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": { "object": "rate", "country_code": "GB", "country_name": "United Kingdom", "eu": false, "standard": { "object": "tax_rate", "rate": 20, "class": "standard", "description": "", "types": false }, "other": [ { "object": "tax_rate", "rate": 5, "class": "reduced", "description": "...", "types": "property renovations" }, { "object": "tax_rate", "rate": 0, "class": "zero", "description": "...", "types": "foodstuffs, books, pharmaceuticals, medical, passenger transport, newspapers, childrens clothing" } ] } } ``` Error (country not subject to VAT): ```json { "success": false, "code": 400, "error": { "title": "No Rates Found", "detail": "The returned country is not subject to VAT." } } ``` ### Find a tax rate `GET /rates/rate` Find a rate that applies to a particular country and optional product type. If no type is provided, or no specific rate applies to the given type, the standard rate is returned. If the country is not subject to VAT/GST, an error is returned. #### Arguments | Argument | Type | Description | |----------|------|-------------| | country_code | string | 2-character country code (ISO 3166-1 alpha-2). | | ip_address | string | IPv4 or IPv6 address. | | province_code | optional | 2-character province code. Requires relevant country_code. | | eu | boolean | Filter by EU membership. | | type | optional | Product type from the list of rate types. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/rates/rate?country_code=FR&type=ebooks' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": { "object": "rate", "country_code": "FR", "country_name": "France", "eu": true, "tax_rate": { "object": "tax_rate", "rate": 5.5, "class": "reduced", "description": "...", "types": "medical, foodstuffs, ebooks, books, water" } } } ``` ### Find a tax rate and VAT price `GET /rates/price` Combines the "Find a tax rate" and "VAT price calculation" endpoints to return the applicable VAT rate and calculated price. #### Arguments | Argument | Type | Description | |----------|------|-------------| | country_code | string | 2-character country code (ISO 3166-1 alpha-2). | | ip_address | string | IPv4 or IPv6 address. | | province_code | optional | 2-character province code. | | eu | boolean | Filter by EU membership. | | type | optional | Product type from the list of rate types. | | price | required | The price to calculate on. Decimal with 2 decimal places (e.g. "30.00"). | | tax_type | required | "incl" or "excl". The tax status of the price you provided. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/rates/price?country_code=FR&type=ebooks&price=20.00&tax_type=incl' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": { "object": "rate", "country_code": "FR", "country_name": "France", "eu": true, "tax_rate": { "object": "tax_rate", "rate": 5.5, "class": "reduced", "description": "...", "types": "medical, foodstuffs, ebooks, books, water" }, "vat_price": { "object": "vat_price", "price": 20, "vat_rate": 5.5, "tax_type": "incl", "price_excl_vat": 18.96, "price_incl_vat": 20, "vat": 1.04 } } } ``` ### Tax rate types `GET /rates/types` Retrieve an array of all product types that specific tax rates apply to. The valid product type values are: `accommodation`, `admission to cultural events`, `admission to entertainment events`, `admission to sporting events`, `advertising`, `agricultural supplies`, `baby foodstuffs`, `bikes`, `books`, `childrens clothing`, `domestic fuel`, `domestic services`, `ebooks`, `electricity`, `electronic services`, `foodstuffs`, `hotels`, `medical`, `newspapers`, `passenger transport`, `pharmaceuticals`, `property renovations`, `restaurants`, `social housing`, `water`, `wine`. Use these values with the `type` parameter on the `/rates/rate` and `/rates/price` endpoints. If no type is provided or no specific rate applies, the standard rate is returned. ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/rates/types' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": { "object": "types", "types": [ "accommodation", "admission to cultural events", "admission to entertainment events", "admission to sporting events", "advertising", "agricultural supplies", "baby foodstuffs", "bikes", "books", "childrens clothing", "domestic fuel", "domestic services", "ebooks", "electricity", "electronic services", "foodstuffs", "hotels", "medical", "newspapers", "passenger transport", "pharmaceuticals", "property renovations", "restaurants", "social housing", "water", "wine" ] } } ``` --- ## Countries The countries object returns a list of all countries, whether they are subject to VAT/GST, and whether they are subject to EU VAT. All countries use the ISO 3166-1 alpha-2 format for country codes. ### List all countries `GET /countries` #### Country object attributes | Attribute | Type | Description | |-----------|------|-------------| | object | string | Value is "country". | | country_code | string | 2-character country code (ISO 3166-1 alpha-2). | | country_name | string | The name of the country. | | latitude | float | Geographic latitude. | | longitude | float | Geographic longitude. | | vat | boolean | Whether the country is subject to VAT/GST. | | eu | boolean | Whether the country is subject to EU VAT. | | provinces | boolean | Whether the country has provinces with provincial sales tax. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/countries' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": [ { "object": "country", "country_code": "AD", "country_name": "Andorra", "latitude": 42.5, "longitude": 1.5, "vat": true, "eu": false, "provinces": false }, { "object": "country", "country_code": "GB", "country_name": "United Kingdom", "latitude": 54, "longitude": -2, "vat": true, "eu": false, "provinces": false } ] } ``` ### Filter countries `GET /countries?country_code={code}` or `GET /countries?ip_address={ip}` | Argument | Type | Description | |----------|------|-------------| | country_code | string | 2-character country code (ISO 3166-1 alpha-2). | | ip_address | string | IPv4 or IPv6 address. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/countries?ip_address=86.27.166.97' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": { "object": "country", "country_code": "GB", "country_name": "United Kingdom", "latitude": 54, "longitude": -2, "vat": true, "eu": false, "provinces": false } } ``` ### List provinces for a country `GET /countries/provinces?country_code={code}` #### Province object attributes | Attribute | Type | Description | |-----------|------|-------------| | object | string | Value is "province". | | country_code | string | 2-character country code. | | province_code | string | 2-character province code. | | province_name | string | The name of the province. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/countries/provinces?country_code=CA' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": [ { "object": "province", "country_code": "CA", "province_code": "AB", "province_name": "Alberta" }, { "object": "province", "country_code": "CA", "province_code": "BC", "province_name": "British Columbia" } ] } ``` --- ## Validate The validate endpoint allows you to check whether a given VAT number is valid. If valid, it returns information about the company. ### Validate response attributes | Attribute | Type | Description | |-----------|------|-------------| | valid | boolean | Whether the VAT number is valid. | | company | object | Information about the company (only present when valid). | | company.vat_number | string | The VAT number. | | company.country_code | string | 2-character country code. | | company.company_name | string | The name of the company. | | company.company_address | string | The address of the company. | | consultation_number | string | Official reference number (only when requester_vat_number is provided). | ### Validate a VAT number `GET /validate?vat_number={vat_number}` VAT validation checks against live UK, EU, Australia, Norway, Switzerland, South Africa, and Brazil records. If the validation database is down, the API returns a 412 error which does not count against your usage. Validation responses are cached for the same day. If the same VAT number is requested again within the same day, the cached response is returned. Exception: if `requester_vat_number` is provided, the cache is bypassed to obtain a fresh consultation number from the live service. This means a request may succeed without `requester_vat_number` (returning a cached result) but fail with it if the upstream service is unavailable. #### Arguments | Argument | Type | Description | |----------|------|-------------| | vat_number | required | The VAT number to check. Must contain the leading 2-character country code (e.g. "GB288305674", "FR12345678901"). | | requester_vat_number | optional | Your own VAT number to receive a consultation number. Must contain the leading 2-character country code. GB requester VAT numbers only work for GB validations, and EU requester VAT numbers only work for EU validations (cross-region is not supported). Australia, Norway, Switzerland, South Africa, and Brazil do not support consultation numbers. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/validate?vat_number=GB288305674' \ --user 'user:' ``` Response (valid): ```json { "success": true, "code": 200, "data": { "valid": true, "company": { "vat_number": "288305674", "country_code": "GB", "company_name": "WEIO LTD", "company_address": "142 CROMWELL ROAD\nLONDON\nGREATER LONDON\n\n\nSW7 4EF" } } } ``` Response (valid, with consultation number): ```json { "success": true, "code": 200, "data": { "valid": true, "company": { "vat_number": "288305674", "country_code": "GB", "company_name": "WEIO LTD", "company_address": "142 CROMWELL ROAD\nLONDON\nGREATER LONDON\n\n\nSW7 4EF" }, "consultation_number": "WAPIAAAAXT9mrLue" } } ``` Response (invalid): ```json { "success": true, "code": 200, "data": { "valid": false } } ``` Response (VIES unavailable): ```json { "success": false, "code": 412, "error": { "title": "VIES Service Unavailable", "detail": "The EU VIES service is temporarily unavailable. Please try again later." } } ``` Response (unsupported country): ```json { "success": false, "code": 400, "error": { "title": "Unsupported Validation Country", "detail": "VAT validation is currently not supported for country code: XX" } } ``` ### Validate an EORI number `GET /validate?eori_number={eori_number}` EORI validation checks against live UK and EU records only. #### Arguments | Argument | Type | Description | |----------|------|-------------| | eori_number | required | The EORI number to check. Must contain the leading 2-character country code (e.g. "GB123456789123"). | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/validate?eori_number=GB123456789123' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": { "valid": true, "company": { "eori_number": "123456789123", "country_code": "GB", "company_name": "EXAMPLE LTD", "company_address": "142 CROMWELL ROAD\nLONDON\nGREATER LONDON\n\n\nSW7 4EF" } } } ``` ### List supported validation countries `GET /validate/countries` Returns a list of all country prefixes supported by the VAT validation service. This endpoint has no parameters. Greece uses prefix "EL" (not GR) per VIES convention, and Northern Ireland uses prefix "XI" for goods-related VAT validation through VIES. #### Response attributes | Attribute | Type | Description | |-----------|------|-------------| | object | string | Value is "validation_prefix". | | prefix | string | The 2-character VAT number prefix. | | country_name | string | The name of the country. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/validate/countries' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": [ { "object": "validation_prefix", "prefix": "AT", "country_name": "Austria" }, { "object": "validation_prefix", "prefix": "AU", "country_name": "Australia" }, { "object": "validation_prefix", "prefix": "BE", "country_name": "Belgium" }, { "object": "validation_prefix", "prefix": "BR", "country_name": "Brazil" }, { "object": "validation_prefix", "prefix": "CH", "country_name": "Switzerland" } ] } ``` --- ## Currency The currency endpoint provides up-to-date currency rates from the official HMRC exchange list and the European Central Bank, as well as currency conversion and VAT price calculation. GBP rates are the official published exchange rates from HMRC, updated on the 1st of every month. EUR rates are the official published rates from the European Central Bank, usually updated around 16:00 CET on every working day. ### List all convert rates `GET /currency` Returns all currency conversion rates from HMRC and European Central Bank. #### Convert rate object attributes | Attribute | Type | Description | |-----------|------|-------------| | object | string | Value is "convert_rate". | | from | string | 3-character currency code converted from (e.g. "USD", "CAD"). | | to | string | 3-character currency code converted to. Either "GBP" or "EUR". | | rate | float | The exchange rate. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/currency' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": [ { "object": "convert_rate", "from": "AED", "to": "GBP", "rate": 4.6039 }, { "object": "convert_rate", "from": "USD", "to": "GBP", "rate": 1.4065 } ] } ``` ### Filter convert rates `GET /currency?from={codes}&to={currency}` Retrieve currency conversion rates filtered by source and target currency. You can only filter to GBP or EUR, as these are provided directly from HMRC and European Central Bank. To convert from GBP or EUR, invert the returned rate. #### Arguments | Argument | Type | Description | |----------|------|-------------| | from | optional | 3-character currency code(s) to convert from. Comma-separated for multiple (e.g. "USD,CAD,AUD"). | | to | required | 3-character currency code to convert to. Must be "GBP" or "EUR". | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/currency?from=USD,CAD,AUD&to=EUR' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": [ { "object": "convert_rate", "from": "AUD", "to": "EUR", "rate": 1.6225 }, { "object": "convert_rate", "from": "CAD", "to": "EUR", "rate": 1.4584 }, { "object": "convert_rate", "from": "USD", "to": "EUR", "rate": 1.0918 } ] } ``` ### Currency conversion `GET /currency/convert?from={from}&to={to}&amount={amount}` Convert a foreign currency amount to GBP or EUR using official exchange rates. #### Arguments | Argument | Type | Description | |----------|------|-------------| | from | required | 3-character currency code to convert from (e.g. "USD"). | | to | required | Must be "GBP" or "EUR". | | amount | required | The amount to convert. Decimal with 2 decimal places (e.g. "39.99"). | #### Response attributes | Attribute | Type | Description | |-----------|------|-------------| | object | string | Value is "conversion". | | from | string | Currency code converted from. | | to | string | Currency code converted to. | | amount | decimal | The original amount. | | converted | decimal | The converted amount. | | rate | float | The exchange rate used. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/currency/convert?from=USD&to=GBP&amount=39.99' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": { "object": "conversion", "from": "USD", "to": "GBP", "amount": 39.99, "converted": 28.43, "rate": 1.4065 } } ``` ### VAT price calculation `GET /currency/price?price={price}&vat_rate={rate}&tax_type={type}` Calculate VAT inclusive and exclusive prices for a given amount and VAT rate. #### Arguments | Argument | Type | Description | |----------|------|-------------| | price | required | The price to calculate on. Decimal with 2 decimal places. | | vat_rate | required | A percentage VAT rate. | | tax_type | required | "incl" or "excl". The tax status of the price provided. | #### Response attributes | Attribute | Type | Description | |-----------|------|-------------| | object | string | Value is "vat_price". | | price | decimal | The price you provided. | | vat_rate | decimal | The VAT rate used. | | tax_type | string | "incl" or "excl". | | price_excl_vat | decimal | Price exclusive of VAT. | | price_incl_vat | float | Price inclusive of VAT. | | vat | float | The total VAT amount. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/currency/price?price=20.00&vat_rate=5&tax_type=excl' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": { "object": "vat_price", "price": 20, "vat_rate": 5, "tax_type": "excl", "price_excl_vat": 20, "price_incl_vat": 21, "vat": 1 } } ``` --- ## Invoices VAT Sense allows you to create VAT-compliant hosted invoices. Invoice totals are automatically calculated from the items provided, depending on the VAT rate, discount rate, and method of tax applied. Invoices must contain your company information. The customer field is optional depending on whether you are creating a "simplified invoice" or "full invoice". Invoices can be either "sale" or "refund" invoices, and can be marked as either inclusive or exclusive of VAT. Every invoice has a unique URL which can be supplied to customers. Adding `/pdf` to the end of the invoice URL will generate a downloadable PDF copy. ### The invoice object | Attribute | Type | Description | |-----------|------|-------------| | id | string | Unique identifier for the invoice. | | object | string | Value is "invoice". | | created | datetime | Date the invoice was created. | | updated | datetime | Date the invoice was last updated. | | date | datetime | Date the invoice was issued. | | tax_point | datetime | The tax point (or "time of supply"). | | type | string | "sale" or "refund". | | tax_type | string | "incl" or "excl". | | currency_code | string | 3-character currency code. | | invoice_number | string | Unique invoice number. | | conversion | object or null | Exchange rate info if billing in a foreign currency. | | conversion.currency_code | string | 3-character currency code for conversion. | | conversion.rate | float | The conversion rate. | | business | object | Your business information. | | business.logo | string | URL to your company logo. | | business.name | string | Your business trading name. | | business.address | string | Your business trading address. | | business.company_number | string | Your business company number. | | business.vat_number | string | Your business VAT number. | | customer | object or false | Customer information. False if not supplied. | | customer.logo | string | URL to the customer logo. | | customer.name | string | Customer trading name. | | customer.address | string | Customer trading address. | | customer.company_number | string | Customer company number. | | customer.vat_number | string | Customer VAT number. | | num_items | int | Number of line items. | | items | list of item objects | The individual items on the invoice. | | totals | object | Invoice totals. | | totals.discount | decimal | Total discount applied. | | totals.subtotal | decimal | Total before VAT. | | totals.vat | decimal | Total VAT applied. | | totals.total | decimal | Total amount of the invoice. | | zero_rated | boolean | Whether the invoice has been zero-rated. | | is_reverse_charge | boolean | Whether zero-rated due to reverse charge. | | invoice_url | string | Unique URL to view the invoice. Append `/pdf` for PDF. | | notes | string | Additional notes. | | has_vat | boolean | Whether VAT is chargeable. | | is_copy | boolean | Whether the invoice is a copy of a primary invoice. | ### Create an invoice `POST /invoice` #### Arguments | Argument | Type | Description | |----------|------|-------------| | date | required | Date the invoice was issued. Format: "YYYY-MM-DD HH:MM:SS". | | tax_point | required | The tax point (time of supply). Format: "YYYY-MM-DD HH:MM:SS". | | type | optional | "sale" or "refund". Default: "sale". | | tax_type | optional | "incl" or "excl". Default: "incl". | | currency_code | required | 3-character currency code. | | invoice_number | optional | Custom invoice number. Auto-increments if not provided. | | serial | optional | Invoice serial prepended to auto-generated number. | | pad_invoice_number | optional | Pad auto-generated number with zeros (2-11). | | conversion | optional | Exchange rate info for foreign currency invoices. | | conversion.currency_code | required | 3-character currency code. | | conversion.rate | required | The conversion rate. | | business | required | Your business information. | | business.logo | optional | URL to logo (HTTPS, .svg/.jpg/.png, 240x60px recommended). | | business.name | required | Trading name. | | business.address | required | Trading address. | | business.company_number | optional | Company number. | | business.vat_number | required | VAT number. | | customer | optional | Customer information. | | customer.logo | optional | URL to logo (HTTPS, .jpg/.png, 240x60px recommended). | | customer.name | required (if customer provided) | Trading name. | | customer.address | optional | Trading address. | | customer.company_number | optional | Company number. | | customer.vat_number | optional | VAT number. | | items | required | Array of line items. | | items[].item | required | Description of the line item. | | items[].quantity | required | Quantity (must be > 0). | | items[].price_each | required | Price per item (decimal, 2 places). | | items[].discount_rate | optional | Percentage discount rate. | | items[].vat_rate | required | Percentage VAT rate. | | zero_rated | optional | Whether the invoice is zero-rated (boolean). | | is_reverse_charge | optional | Whether zero-rated due to reverse charge. | | notes | optional | Additional notes. | | has_vat | optional | Whether VAT is chargeable (boolean). | | is_copy | optional | Whether this is a copy of a primary invoice. | ``` curl --request POST \ --url 'https://api.vatsense.com/1.0/invoice' \ --user 'user:' \ --header 'content-type: application/json' \ --data '{ "date": "2018-06-03 14:02:00", "tax_point": "2018-06-03 14:02:00", "type": "sale", "tax_type": "incl", "currency_code": "USD", "invoice_number": "203", "conversion": { "currency_code": "GBP", "rate": 1.523 }, "business": { "logo": "https://example.com/logo.png", "name": "Example Company", "address": "123 Example Street\nLondon\nSW3 1GL\nUnited Kingdom", "vat_number": "GB12345678", "company_number": "9839222" }, "customer": { "name": "Customer Co.", "address": "65 Demo Road\nLondon\nSW1 3DE\nUnited Kingdom", "vat_number": "GB912343332", "company_number": "5584922" }, "items": [ { "item": "Standard payment plan", "quantity": 1, "price_each": 19.99, "vat_rate": 20, "discount_rate": 40 } ], "notes": "Thank you for your business" }' ``` ### Retrieve an invoice `GET /invoice/{invoice_id}` | Argument | Type | Description | |----------|------|-------------| | invoice | required | The unique invoice identifier. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/invoice/in5aeae457cda2a' \ --user 'user:' ``` ### Update an invoice `PATCH /invoice/{invoice_id}` Pass only the data you wish to update. Any arguments used to create an invoice can be passed. ``` curl --request PATCH \ --url 'https://api.vatsense.com/1.0/invoice/in5aeae457cda2a' \ --user 'user:' \ --header 'content-type: application/json' \ --data '{"customer":{"name":"Updated Co."}}' ``` ### Delete an invoice `DELETE /invoice/{invoice_id}` Permanently deletes an invoice. Returns a 200 response on success. ``` curl --request DELETE \ --url 'https://api.vatsense.com/1.0/invoice/in5aeae457cda2a' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200 } ``` ### List all invoices `GET /invoice` Returns invoices sorted by creation date (most recent first). Default limit is 10, maximum is 100. | Argument | Type | Description | |----------|------|-------------| | limit | optional | Number of invoices per request (1-100). Default: 10. | | offset | optional | Offset for pagination. Min: 0. | | search | optional | Search by business name or customer name. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/invoice' \ --user 'user:' ``` --- ## Invoice items You can update or delete specific invoice items without updating the entire items list. ### The item object | Attribute | Type | Description | |-----------|------|-------------| | id | string | Unique identifier for the item. | | object | string | Value is "item". | | item | string | Description of the line item. | | quantity | int | Quantity (must be > 0). | | price_each | decimal | Price per item. | | discount_rate | float | Percentage discount rate. | | vat_rate | float | Percentage VAT rate. | | price_total | decimal | Total price for the item. | Example: ```json { "id": "ii5aeae457ce201", "object": "item", "item": "Standard payment plan", "quantity": 1, "price_each": 19.99, "discount_rate": 40, "vat_rate": 20, "price_total": 11.99 } ``` ### Add items `POST /invoice/{invoice_id}/item` Add new items to an invoice. | Argument | Type | Description | |----------|------|-------------| | items | required | Array of items to add. | | items[].item | required | Description of the line item. | | items[].quantity | required | Quantity (must be > 0). | | items[].price_each | required | Price per item (decimal, 2 places). | | items[].discount_rate | optional | Percentage discount rate. | | items[].vat_rate | required | Percentage VAT rate. | ``` curl --request POST \ --url 'https://api.vatsense.com/1.0/invoice/in5aeae457cda2a/item' \ --user 'user:' \ --header 'content-type: application/json' \ --data '{"items":[{"item":"Additional item","quantity":1,"price_each":3.99,"vat_rate":20}]}' ``` ### Update an item `PATCH /invoice/{invoice_id}/item/{item_id}` Pass only the data you wish to update. Once updated, invoice totals are automatically recalculated. ``` curl --request PATCH \ --url 'https://api.vatsense.com/1.0/invoice/in5aeae457cda2a/item/ii5aeae457ce201' \ --user 'user:' \ --header 'content-type: application/json' \ --data '{"item":"Updated item name"}' ``` ### Delete an item `DELETE /invoice/{invoice_id}/item/{item_id}` Permanently deletes an item. Invoice totals are automatically recalculated. You cannot delete an item if it is the only remaining item. ``` curl --request DELETE \ --url 'https://api.vatsense.com/1.0/invoice/in5aeae457cda2a/item/ii5aeae457ce201' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200 } ``` --- ## Usage `GET /usage` Check your used and remaining requests. **Note:** For free plans, usage lookup requests count towards your quota to prevent abuse. Paid plans can use the usage endpoint without affecting their quota. ### Response attributes | Attribute | Type | Description | |-----------|------|-------------| | requests | object | API usage information. | | requests.total | int | Total requests allowed per your plan. | | requests.used | int | Requests used in the last 30 days. | | requests.remaining | int | Requests remaining before the limit is reached. | ``` curl --request GET \ --url 'https://api.vatsense.com/1.0/usage' \ --user 'user:' ``` Response: ```json { "success": true, "code": 200, "data": { "requests": { "total": 100, "used": 23, "remaining": 77 } } } ``` --- ## Frequently asked questions ### General **What is VAT Sense?** VAT Sense is a developer-friendly REST API for VAT and GST compliance. It provides VAT number validation for UK, EU, Australia, Norway, Switzerland, South Africa, and Brazil; EORI number validation for UK and EU; VAT and GST rates for all countries; currency conversion with official HMRC and ECB rates; and VAT-compliant invoice generation. All plans include 256-bit SSL encryption. **Where does the API data come from?** Official government sources: UK VAT validation via HMRC API (v2.0), EU VAT validation via VIES (European Commission), Australia via ABN Lookup API, Norway/Switzerland/South Africa/Brazil via official government systems. GBP exchange rates from HMRC, EUR exchange rates from the European Central Bank. **Is VAT Sense secure?** Yes. All plans use 256-bit SSL encryption. Servers are based in London, UK. VAT Sense never sells your data and is fully GDPR compliant. **Where is VAT Sense based?** UK company based in London and Manchester, working with digital VAT solutions for over 10 years. ### VAT validation **Which countries can I validate VAT numbers for?** United Kingdom (via HMRC), European Union (all 27 member states via VIES), Australia (ABN/GST), Norway (MVA), Switzerland (UID), South Africa, and Brazil (CNPJ). EORI validation is supported for UK and EU. **What happens when VIES is unavailable?** You'll receive a 412 error response. VAT Sense has access to fallback VIES endpoints providing approximately 10-15% improved reliability. Failed requests due to service unavailability do not count against your monthly quota. Implement retry logic for 412 errors. **Do failed requests count against my quota?** No. If a validation request fails due to service unavailability (412 error), it does not count against your monthly quota. **What is a consultation number?** An official reference issued by VIES (EU) or HMRC (UK) when you validate a VAT number, serving as proof of the check at a specific date and time. Include your own VAT number as the `requester_vat_number` parameter to receive one. GB requester VAT numbers only work for GB validations, and EU requester VAT numbers only work for EU validations. Australia, Norway, Switzerland, South Africa, and Brazil do not support consultation numbers. **Do you support EORI validation?** Yes, for both UK and EU EORI numbers. **Do I need to register with HMRC to validate UK VAT numbers?** No. VAT Sense is pre-integrated with HMRC's v2.0 API. **Can I get company details from a VAT number?** Yes. Validation returns the company name, country code, and address (where available). **Can I validate multiple VAT numbers in one request?** The API validates one VAT number per request. For bulk validation, make multiple API calls in parallel. Schedule bulk operations during off-peak hours for best reliability. **Can I use VAT Sense for e-commerce checkout?** Yes. With under 15ms average response time, it's well-suited for real-time checkout validation. Note: VAT Sense does not support CORS, so all API calls must be made server-side. Never expose your API key in client-side code. ### Data and rates **Does VAT Sense provide VAT rates for all EU countries?** Yes, for all 27 EU member states plus VAT/GST rates worldwide. **How up to date is the data?** VAT validations: real-time. GBP exchange rates: updated 1st of every month. EUR exchange rates: updated daily around 16:00 CET on working days. VAT rates: updated as countries announce changes. **Can I look up VAT rates by IP address?** Yes, using the rates endpoint with the `ip_address` parameter. **Can I create VAT-compliant invoices?** Yes, with full CRUD operations via the invoice endpoints. ### API access **How do I access the API?** Create a free account at vatsense.com/signup to get your API key. Start making requests immediately using HTTP Basic Auth. **What is a request?** A single API call. Each plan includes a number of requests measured on a rolling 30-day window. **What happens if I exceed my request limit?** Email notifications are sent at 75%, 90%, and 100% of your limit. At 100%, requests return a 429 error. You won't be charged for exceeding, and you can upgrade at any time. **What is the API uptime?** Over 99.9% uptime with under 15ms average response time. VAT validation depends on external government services which may occasionally be unavailable (412 errors). **Is there a rate limit?** Yes: 300 requests per minute (general) and 3 requests per second (UK VAT validation only, per HMRC requirements). Implement exponential backoff for 429 responses. **Do you offer SDKs or client libraries?** Yes. Official client libraries are available for Python (`pip install vatsense`), Node.js/TypeScript (`npm install vat-sense`), PHP (`composer require vatsense/vatsense-php`), Go (`go get github.com/VAT-Sense/vatsense-go`), Ruby (`gem install vatsense`), C#/.NET (`dotnet add package vatsense`), and Java (Maven Central). All libraries include authentication, automatic retries, and typed responses. See https://vatsense.com/libraries for full details and code examples. --- ## Official libraries and SDKs Official client libraries are available for all major programming languages. Each library handles authentication, request formatting, error handling, automatic retries with exponential backoff, and fully typed responses. All libraries are open source under the Apache 2.0 licence. | Language | Install | GitHub | |----------|---------|--------| | Python | `pip install vatsense` | https://github.com/VAT-Sense/vatsense-python | | Node.js / TypeScript | `npm install vat-sense` | https://github.com/VAT-Sense/vatsense-node | | PHP | `composer require vatsense/vatsense-php` | https://github.com/VAT-Sense/vatsense-php | | Go | `go get github.com/VAT-Sense/vatsense-go` | https://github.com/VAT-Sense/vatsense-go | | Ruby | `gem install vatsense` | https://github.com/VAT-Sense/vatsense-ruby | | C# / .NET | `dotnet add package vatsense` | https://github.com/VAT-Sense/vatsense-csharp | | Java | Maven Central | https://github.com/VAT-Sense/vatsense-java | For full installation instructions and code examples, see https://vatsense.com/libraries ## Pricing | Requests/month | GBP | USD | EUR | |----------------|-----|-----|-----| | 100 | Free | Free | Free | | 500 | £4.99 | $6.99 | €5.99 | | 2,000 | £9.99 | $13.99 | €11.99 | | 10,000 | £29.99 | $39.99 | €34.99 | | 25,000 | £59.99 | $79.99 | €69.99 | | 50,000 | £99.99 | $129.99 | €119.99 | 20% discount for annual upfront payment. Enterprise plans available on request. The free plan lasts forever with no time limit.