Integrating a VIES VAT API Into Your Systems

Integrating a VIES VAT API means calling it from a business event – someone signs up, an order is placed, an invoice is raised – instead of pasting numbers into a web form. One authenticated GET returns whether the number is currently registered, the company name and address behind it, a checkId for your own records, and, once you set your own VAT as requester, the VIES consultation number: a reference proving the check was made against VIES at a given date and time.

Where to trigger the check

Customer onboarding

The buyer types a VAT number into a signup or account form. Checking it here catches the typo while someone is still looking at the screen, and it decides whether the account is business or consumer.

Checkout or order creation

The tax treatment of the order depends on the answer, so the check belongs in the same request that prices the order — not in a nightly batch.

Invoice generation

A number that was valid at signup can have lapsed by the time you invoice. Re-check at invoice time.

Most systems end up with two of these rather than one: a cheap check at onboarding to keep bad data out, and a second at invoice time because that is the moment the record has to stand on its own. A check is true as of its timestamp and says nothing about the week after.

The integration pattern

The call itself is an ordinary HTTP request, made from an event handler, a queue worker, or an automation step in a platform you do not control:

on invoice created
async function onInvoiceCreated(invoice) {
  const res = await fetch(`https://api.vatnode.dev/v1/vat/${invoice.buyerVatId}`, {
    headers: { Authorization: `Bearer ${process.env.VATNODE_API_KEY}` },
  })

  // 5xx and network errors are worth retrying with backoff.
  // A 4xx is an answer, not an outage - do not retry it.
  if (res.status >= 500) throw new RetryableError(`vatnode ${res.status}`)

  const check = await res.json()

  await invoices.update(invoice.id, {
    buyerVatValid: check.valid,
    buyerVatCheckId: check.checkId,
    buyerVatConsultationNumber: check.consultationNumber,
    buyerVatCheckedAt: check.verifiedAt,
  })

  return check.valid
}

Three things to get right before that goes to production.

  • Retry outages, not verdicts. A 5xx or a timeout means the check did not happen and is safe to repeat. A 4xx is the answer – an invalid number, a malformed one, a rejected requester – and repeating it changes nothing. Error codes are listed in the error reference.
  • Read the quota headers in your own logs. Every live response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset, so you see the ceiling approaching before anything is refused. Details in the rate-limit docs.
  • The requester VAT is account-level. You set it once in the dashboard and every check carries it from then on – there is no per-call parameter to thread through each code path.

What to store

Put the result on the record it justifies. The consultation number belongs next to the invoice, because it is the part that came back from VIES rather than from your own system; checkId and verifiedAt are vatnode’s internal reference and timestamp, useful for looking a check up later. What to keep and for how long is the subject of the audit-trail guide; retention obligations vary by country, so confirm yours with a tax advisor.

Connecting from an ERP, accounting or invoicing system

These systems rarely run your code. The call usually happens in one of three places: the platform’s own scripting or extensibility layer, an automation tool sitting beside it, or a small service of your own that the platform calls instead. Which one you pick matters less than where the result lands – the check is only useful if the validity flag and the consultation number end up on the order or invoice record the platform already keeps.

If the platform can make an authenticated outbound HTTPS request and store a few fields, it can use vatnode. There is an n8n node and a WooCommerce plugin if either fits your stack; everything else is the REST call above.

Frequently Asked Questions

Can I call vatnode from Sage 1000?

Yes, through the outbound HTTP call in its own automation layer — the same way you would reach any external REST service. There is no native vatnode connector for it; what the platform needs is the ability to make an authenticated HTTPS GET to api.vatnode.dev and write two or three fields back onto the record.

Can I call vatnode from Microsoft Dynamics AX?

Same answer: an outbound HTTPS call from the platform’s own extensibility layer, or from middleware sitting between it and vatnode. No native connector exists. The response is plain JSON, so whatever the platform uses to parse an HTTP response is enough.

Can I call vatnode from Sage 300?

Yes, on the same terms as any other ERP — an outbound HTTPS call and a place to store the result. If the platform cannot make that call directly, put an automation step in front of it.

Is there a ready-made integration I do not have to build?

There is an n8n node and a WooCommerce plugin, both published. Anything else is the REST call described on this page — one authenticated GET, JSON back.

Do I need to pass my own VAT number on every call?

No. The requester VAT is set once in the dashboard, under Account details, and applies to every check from then on. There is no per-call parameter for it.

Put the check in your pipeline

Free plan, no credit card. One authenticated GET, JSON back – from any language or any platform that can make an HTTPS request.