Skip to content

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 : false
Whether a record is written for each collected payment. Off, nothing is written and nothing is retroactive: payments collected while it was off stay out of the ledger for good.
inclusivebooleanoptionaldefault : false
Whether the amounts you charge already contain tax. False means the tax is computed on top of the amount.
default_countrystringoptional
Two letters. Used when the payer country could not be resolved, and as the country the reverse charge rule compares against. Defaults to your account country, then CM.
tax_id_typestringrequired
The kind of registration you hold, such as cm.niu, ci.ifu, ke.pin or eu.vat. Stored as given.
registration_numberstringrequired
Your own number. Stored as given, and never shown to your payers by Wajub.

One 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.

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.

ConditionHow it is checked
The customer is a businessTheir type is business, not an individual
They hold a verified tax IDAt least one of their tax IDs has reached verified
They are in another countryTheir 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.

POSThttps://api.wajub.com/customers/{customer_id}/tax_ids

The type is what decides how the value is checked, so use the real one rather than a generic word.

Register a customer's NIU
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.

TypeFormat checked
cm.niuM then nine digits then a letter
ci.ifuSeven digits then a letter
sn.nineaSeven digits, a letter, a digit, a letter
ke.pinP then nine digits then a letter
ng.tinEight digits, a dash, four digits
gh.vatTen to fifteen letters or digits
za_vatTen digits
gb.vatGB then nine or twelve digits
us.einTwo digits, a dash, seven digits
au_abnEleven digits
eu.vatTwo letters then two to thirteen letters or digits

Spaces, dashes and dots are stripped before the check. Four statuses come out of it.

StatusMeaning
pendingQueued, not yet checked
verifiedThe check passed. This is the only status the reverse charge accepts
failedThe format is wrong, or the registry says the number is invalid
unavailableThe 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.

Calculate with a tax code
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.

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.

What did you think of this content?