Tax
Enable tax collection, calculate it, and manage your registrations.
Tax turns a rate table and a set of registrations into an amount on every payment. Once you
switch it on, each transaction is taxed and recorded automatically, and a tax object appears on
payment and refund responses. Until then, these endpoints let you look up rates and try
calculations without committing to anything.
Live only, private key
Every /tax endpoint needs a private key (sk.) or a restricted key with tax.read or
tax.write, and refuses a sandbox key with
403 This feature is only available in live mode.
Settings
https://api.wajub.com/tax/settingscurl https://api.wajub.com/tax/settings \
-H "Authorization: $WAJUB_API_KEY"The configuration comes back under tax:
enabledbooleanoptionalinclusivebooleanoptionaltrue means the amount you send already contains the tax; false means tax is added on top.default_countrystringoptionaltax_id_typestringoptionaltax_registration_numberstringoptionalTurning tax on is a PUT on the same path. enabled: true makes tax_id_type and
registration_number mandatory in the same request, and the number is checked against the format
expected for its type.
curl -X PUT https://api.wajub.com/tax/settings \
-H "Authorization: $WAJUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"inclusive": true,
"default_country": "CM",
"tax_id_type": "vat",
"registration_number": "M071812345678A"
}'The request field is `registration_number`
You write registration_number and you read tax_registration_number. The two names refer to
the same value; only the direction differs.
Calculating before charging
POST /tax/calculate answers the question "what will this cost with tax" without creating
anything. Use it to show a total at checkout.
https://api.wajub.com/tax/calculateamountnumberrequiredcountrystringrequiredcurrencystringoptionaldefault : XAFtax_inclusivebooleanoptionaldefault : falseamount already contains the tax.customer_idstringoptionaltax_codestringoptionalcurl https://api.wajub.com/tax/calculate \
-H "Authorization: $WAJUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 25000,
"currency": "XAF",
"country": "CM",
"customer_id": "cus_01JXXXXXXXXXXXXX"
}'total is the figure to show the customer, and the figure to pass as amount when you create
the payment:
Exempt and reverse charge are answers, not errors
When customer_exempt or reverse_charge is true, tax_amount is zero and total equals
amount. That is a correct calculation for a customer who holds a verified tax ID in a
reverse-charge jurisdiction, not a failure to calculate.
Reference data
Read-only lists, identical for every merchant. None of them accepts a cursor; the two that
paginate use per_page, default 50 and maximum 100.
| Endpoint | Returns under | Filters | Paginated |
|---|---|---|---|
GET /tax/rates | rates | country | No |
GET /tax/codes | tax_codes | category | Yes |
GET /tax/codes/{code} | tax_code | n/a | |
GET /tax/jurisdictions | jurisdictions | country, state, type | Yes |
GET /tax/thresholds | thresholds | country | No |
GET /tax/rates is the shortest of them, one standard rate per country:
jurisdiction_type on a jurisdiction is one of country, state, county, city or
district, and is_compound says whether its rate stacks on top of a parent's rather than
replacing it.
GET /tax/codes/{code} returns one code plus every country rate attached to it, under rates,
so a single call tells you how a product category is taxed everywhere you sell.
Registrations
Where you are registered to collect tax. Five endpoints, the usual shape, all scoped to your team.
| Method | Endpoint | Returns |
|---|---|---|
GET | /tax/registrations | registrations |
POST | /tax/registrations | registration, 201 |
GET | /tax/registrations/{id} | registration |
PUT | /tax/registrations/{id} | registration |
DELETE | /tax/registrations/{id} | confirmation |
country_codestringrequiredstate_codestringoptionaltypestringoptionalstandard, simplified, ioss, oss.registration_numberstringoptionalregistered_atdateoptionalexpires_atdateoptionalregistered_at.A new registration is created with status: "active".
Thresholds and alerts
Many jurisdictions only require registration past a turnover threshold. GET /tax/thresholds
lists them; GET /tax/thresholds/alerts compares them against your own volume and returns the
countries where you are approaching or already past the line.
curl https://api.wajub.com/tax/thresholds/alerts \
-H "Authorization: $WAJUB_API_KEY"Customer tax IDs
A customer's own tax IDs live under the customer, not under /tax. Adding one queues an
asynchronous verification, so the ID comes back with verification_status: "pending" and settles
later.
| Method | Endpoint | Returns |
|---|---|---|
GET | /customers/{customer_id}/tax_ids | tax_ids |
POST | /customers/{customer_id}/tax_ids | tax_id, 201 |
DELETE | /customers/{customer_id}/tax_ids/{id} | confirmation |
typestringrequiredvaluestringrequiredcountry_codestringrequiredTax IDs change the calculation
A verified tax ID is what makes customer_exempt or reverse_charge come back true from
POST /tax/calculate. Add the ID before you calculate, not after.
Reports
GET /tax/reports aggregates tax collected over a period. It accepts period, one of 7d,
30d, 90d, month, year or custom, plus start_date and end_date for custom, and
optional currency and country filters. The result comes back under report.