Configuration
Settings, inclusive pricing, exemptions, reverse charge and customer tax IDs.
Five settings decide how Tax behaves for your account, and two customer-level rules can override the outcome on a given payment. This page is all of them, in the order the engine reads them.
Your settings
enabledbooleanoptionaldefault : falseinclusivebooleanoptionaldefault : falsedefault_countrystringoptionaltax_id_typestringrequiredregistration_numberstringrequiredOne asymmetry to know about when you script this: you write registration_number and you read it
back as tax_registration_number. The other four keep their names in both directions.
Your own registration is recorded, not used
Neither field changes a single calculation. They exist so your account carries the identity you file under. The rate applied to a payment never depends on who you are, only on where your payer is.
Inclusive or exclusive
The switch changes which of the two numbers you already know.
Exclusive, the default. Your amount is the base. tax = amount × rate, and the customer owes
amount + tax. On 10 000 XAF at 19.25 %, the tax is 1 925 and the total is 11 925.
Inclusive. Your amount is the total. base = amount ÷ (1 + rate) and the tax is what is left.
On 10 000 XAF at 19.25 %, the base is 8 386 and the tax is 1 614. The customer still pays 10 000.
The choice is a property of your prices, not of a payment. Pick the one that matches how you quote and leave it alone: changing it changes what every future record means, and the past is not recomputed.
The setting applies to the records written on your payments. POST /tax/calculate does not read
it: send tax_inclusive: true in the request when you want an inclusive calculation, otherwise it
is exclusive.
Rounding
Tax is rounded to the currency's own precision, not to two decimals everywhere. XAF, XOF, RWF, UGX, KMF, GNF, BIF, DJF, JPY, KRW and the other zero decimal currencies round to whole units; KWD, BHD, OMR, JOD and TND round to three decimals; everything else rounds to two.
This is why an XAF calculation never comes back with cents, and why the same 19.25 % on the same amount gives a different-looking figure in EUR.
Which country the rate comes from
On a recorded payment, three steps in order: the country resolved from the payer's IP when the
payment page opened, then your default_country, then CM.
On POST /tax/calculate, one step: the country you sent. It is required, and nothing falls
back to it.
The currency is never consulted. A payer in France paying you in XAF is charged French TVA at 20 %, because tax follows where the service is consumed.
Exempt customers
A customer marked exempt produces a calculation with a rate of zero, customer_exempt: true, and
no tax at all. It takes priority over everything else, the reverse charge included.
There is no way to mark a customer exempt today
No endpoint and no Dashboard form sets the exemption flag on a customer, so every customer is
none in practice. Until that changes, the working exemption is the
reverse charge below.
Reverse charge
When it applies, the tax is zero and reverse_charge: true comes back: the tax is owed by your
customer in their own country, not collected by you. Three conditions, all required.
| Condition | How it is checked |
|---|---|
| The customer is a business | Their type is business, not an individual |
| They hold a verified tax ID | At least one of their tax IDs has reached verified |
| The payment comes from another country | The country of the calculation differs from your default_country |
The country of the calculation is the one the rate comes from: the country you send to
POST /tax/calculate, or on a recorded payment the payer's country resolved when the payment page
opened. The customer's own country is not read. A foreign business paying you from your own country
is taxed like anyone else there.
Nothing else is looked at. In particular the economic zone is not a condition: a Cameroonian merchant paid by a verified business from Senegal, from Germany or from Japan gets the same reverse charge, and paid from Cameroon does not.
A tax ID only ever leads to the reverse charge. It never makes a customer exempt: that flag is separate, and nothing writes it (above).
The conditions are read on the calculation, so a tax ID still pending verification gives you a normal taxed result. Register the ID first, wait for it to verify, then calculate.
Customer tax IDs
A tax ID belongs to a customer and is registered once, separately from any payment.
https://api.wajub.com/customers/{customer_id}/tax_idsThe type is what decides how the value is checked, so use the real one rather than a generic
word.
curl https://api.wajub.com/customers/cus_sAaim5apjocIgtlhzJY3wQ8s/tax_ids \
-H "Authorization: sk.xxxxxxxxxxxxxxxx…" \
-H "Content-Type: application/json" \
-d '{
"type": "cm.niu",
"value": "M071512345678A",
"country_code": "CM"
}'The call returns immediately with verification_status: "pending" and verification runs in the
background. There is no webhook for it, so read the tax ID back when you need to know. These routes
sit under /customers: a restricted key needs customer.read and customer.write, not the tax
permissions.
A customer's number is checked against the same list of formats as your own registration number.
| Type | Format checked |
|---|---|
cm.niu | A letter, twelve digits, a letter |
ci.ifu | Thirteen digits |
sn.ninea | Eight digits, a letter, a digit |
ke.pin | A letter, nine digits, a letter |
ng.tin | Eight digits, a dash, four digits |
gh.tin | For a business, C, G, P, Q or V, then 00 and eight digits (C0001234567). For an individual, the Ghana Card PIN: three letters, eight or nine digits and a check character (GHA-123456789-0) |
gh.vat | The same number as gh.tin, which Ghana files VAT under |
za_vat | 4 then nine digits |
gb.vat | GB then nine digits |
us.ein | Two digits, a dash, seven digits |
au_abn | Eleven digits |
eu.vat | The format of the member state its prefix names: DE then nine digits, FR then two letters or digits and nine digits, and so on. Greece is EL |
A number is accepted with or without the spaces, dashes, dots and slashes its format writes:
12-3456789 and 123456789 are the same EIN. Adding the same type and number again does not add a
copy: the call answers 200 with the existing entry, back to pending while it is checked again.
Four statuses come out of the check.
| Status | Meaning |
|---|---|
pending | Queued, not yet checked |
verified | The check passed. This is the only status the reverse charge accepts |
failed | The format is wrong, or the registry says the number is invalid |
unavailable | The registry could not be reached. Retry by adding the same number again |
Only EU VAT is checked against a registry
An eu.vat number is sent to the European VIES service, which answers whether it really exists
and returns the registered name. Other types are checked for format only. Wajub does not
confirm the number is registered, so verify it yourself before relying on the reverse charge.
Product tax codes
A tax code says what you are selling, so that a jurisdiction can apply something other than its
standard rate to it. Pass one on a calculation, or put tax_code in a payment's metadata and the
record picks it up.
curl https://api.wajub.com/tax/calculate \
-H "Authorization: sk.xxxxxxxxxxxxxxxx…" \
-H "Content-Type: application/json" \
-d '{
"amount": 10000,
"currency": "XAF",
"country": "CM",
"tax_code": "txcd_10103001"
}'Two behaviours are worth knowing before you rely on one. txcd_00000000 is the nontaxable code:
when the catalogue carries it, it forces a rate of zero in every country. And a code the catalogue
has no rate for falls back to the country's standard rate, silently, with the code echoed back in
the response so the result looks like it was applied.
List the catalogue before you depend on a code
GET /tax/codes is the only authority on which codes exist and which countries carry a rate for
them, and GET /tax/codes/{code} shows that code's rates country by country. A code that is
absent does not error, it just gives you the standard rate. Check the catalogue rather than
assuming a code from another provider maps across.
A tax code is also ignored entirely when the customer is exempt or the reverse charge applies. Those are settled first.
Sub-national rates
Some countries tax at the state, county or city level rather than nationally.
GET /tax/jurisdictions lists what Wajub holds, filterable by country, state and level, with each
entry's rate and whether it compounds on the ones before it.
A payment is recorded at the country's standard rate, the one POST /tax/calculate answers with.
A payment carries no state or city, so sub-national rates are listed but not applied.
Where you are registered
/tax/registrations keeps a list of the jurisdictions you are registered in, with a type among
standard, simplified, ioss and oss, your number there, and the dates it runs between.
It is a filing aid, not a switch. No calculation and no record consults it, so adding a
registration never changes a rate and removing one never stops a record from being written.
Deleting revokes the entry rather than erasing it: the entry is kept as revoked for your
history. There is one entry per country and state, so registering the same country and
state again answers 422, a revoked entry included: set it back with PUT and status: "active".