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 385 and the tax is 1 615. 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.
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; 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
The flag is readable on a customer and read by the engine, but no endpoint and no Dashboard form
writes it. 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 |
| They are in another country | Their country differs from your default_country |
Nothing else is looked at. In particular the economic zone is not a condition: a Cameroonian merchant selling to a verified business in Senegal, in Germany or in Japan gets the same reverse charge, and selling to a verified business in Cameroon does not.
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.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i…" \
-H "Content-Type: application/json" \
-d '{
"type": "cm.niu",
"value": "M071512345A",
"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.
| Type | Format checked |
|---|---|
cm.niu | M then nine digits then a letter |
ci.ifu | Seven digits then a letter |
sn.ninea | Seven digits, a letter, a digit, a letter |
ke.pin | P then nine digits then a letter |
ng.tin | Eight digits, a dash, four digits |
gh.vat | Ten to fifteen letters or digits |
za_vat | Ten digits |
gb.vat | GB then nine or twelve digits |
us.ein | Two digits, a dash, seven digits |
au_abn | Eleven digits |
eu.vat | Two letters then two to thirteen letters or digits |
Spaces, dashes and dots are stripped before the check. Four statuses come out of it.
| 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 registering it 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. Every other type is checked against its expected shape and
nothing more: a well-formed number that belongs to nobody comes back verified. A type that is
not in the table above passes on length alone, between five and twenty characters.
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.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i…" \
-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.
When more than one jurisdiction matches a payment's location, the record carries their sum and a breakdown. When none does, the country's standard rate applies, which is the case everywhere Wajub has no sub-national data.
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 status becomes revoked and the row stays
for your history.