Reports
The ledger, how refunds net out, the export, and what is not in it.
Every collected payment leaves one row, every refund leaves a negative one, and the report is that ledger summed over a period. Nothing is recomputed at read time, so a report of last quarter shows the rates that applied then, not the rates that apply now.
What goes into the ledger
A row is written when the payment is credited, not when it is created and not when it is attempted. Four things stop it.
| Condition | Result |
|---|---|
| Tax is off on your account | No row, and no catching up later if you switch it on |
| The payment is a sandbox one | No row, ever |
| The payment is a funding top-up of your own balance | No row |
| The computed tax is zero | No row, so a zero-rated country leaves nothing behind |
The row is written once per payment. A second attempt on the same payment, or a replay of the event, never duplicates it.
A refund writes a negative row
Refund a payment and the ledger reverses the tax in the same proportion. Refund a third of the amount and a third of the tax comes back, at the original rate, against the original country, with both amounts negative.
That proportion is capped at the whole: refunding more than the recorded base still reverses at most one hundred percent of the tax. And when the original payment left no row, the refund leaves none either: no tax was collected on it, so none is given back. That covers a payment taken while Tax was off, an exempt customer, a reverse-charge sale and a zero-rated product.
The payment's row alone decides, not your settings on the day of the refund. Tax recorded on a payment was collected, so its refund reverses its share even after you switch Tax off or your plan stops covering it. Switching Tax on later never gives a payment that has no row a reversal either.
The consequence is the one you want at filing time: the report nets collections against reversals on its own, and you never subtract anything by hand.
The report
https://api.wajub.com/tax/reportsFive query parameters, all optional, and the two filters narrow the whole payload rather than adding a section to it.
periodenumoptionaldefault : 30dstart_datedateoptionalend_datedateoptionalcountrystringoptionalcurrencystringoptionalThe response nests everything under report, and gives you the same figures three times: once as a
total, once per country, once per currency.
Three details matter when you reconcile against your own books. tax_collected counts only
positive rows and tax_reversed only negative ones, so net_tax is their sum and is the figure
you file. transactions counts every row in the group, reversals included, so a country with
three hundred payments and twelve refunds reports three hundred and twelve. And summary.currency
is whatever you filtered on, or the first currency found: on a multi-currency account the summary
adds amounts across currencies, which is only meaningful once you have filtered to one.
File country by country, one currency at a time
You owe tax to a jurisdiction in its own currency, so the report you act on is the one with both
country and currency set. by_country on an unfiltered report is useful for spotting where
you have exposure, not for filling in a return.
The Dashboard report is not the same object
Tax in the Dashboard answers the same question with a different payload, so do not expect the two to line up field for field.
| API | Dashboard | |
|---|---|---|
| Period | start_date and end_date | A period object with start and end |
| Total | summary.total_tax_collected | total_tax |
| Per row | tax_collected and transactions | tax_amount and count |
| Collections and reversals | Split into two fields | Summed into one |
| Across currencies | Not converted | Converted into your base currency as global_total |
| Rates | Absent | The rate table is included alongside |
The Dashboard one nets collections and reversals into a single figure per row, which is why a month
with refunds reads lower there than tax_collected does on the API. Both are right, they answer
slightly different questions.
The CSV export
Tax, then export, downloads the current view as a semicolon-separated CSV with a UTF-8 marker, so Excel opens it correctly in French and Portuguese locales without an import step. It carries the period, the totals, the base currency conversion when you trade in several, then one block per country and one per currency.
Exports count against your plan's monthly quota: ten a month on Pay as you go, unlimited from Growth up. There is no export on the API.
Registration thresholds
Many jurisdictions only require you to register once your local revenue crosses a line.
GET /tax/thresholds lists the thresholds Wajub tracks, with the amount, the currency and the
period each is measured over.
GET /tax/thresholds/alerts compares them against your own recorded revenue over each threshold's
own period (the calendar year, a rolling twelve months or the quarter) and returns only what needs
attention: approaching from 80 % of the line, and exceeded at 100 %. An empty array means
nothing is close, and it is also what you get before any tax has been recorded.
Your revenue is converted into the threshold's currency at the platform's rates before it is
compared: sales in XAF count towards a threshold in GBP at their value in pounds. The EU threshold
counts your sales in every member state together. A threshold your revenue cannot be converted for,
a currency without a rate, is not measured and raises no alert.
A threshold set for a state rather than a whole country (one with a state_code, such as a US
state's economic nexus) is listed by GET /tax/thresholds but never comes back as an alert: a tax
row records the country, not the state, so there is nothing to measure it against.
The comparison is against what Wajub recorded
Your local revenue here is the sum of taxable_amount on your positive tax rows, over the
threshold's period, converted into its currency. Revenue collected before you turned Tax on is not
in it, and neither is anything you invoiced outside Wajub. Treat the alert as a prompt to check,
not as a legal position.
What the ledger does not hold
Worth knowing so you do not look for exports that are not there.
No sub-national rate. A row is written at the country's standard rate, the one
POST /tax/calculate gives: a payment carries no state or city to apply a sub-national rate to.
No mobile money levy and no digital services tax. Mobile money levies and digital services taxes are not recorded, shown on a payment, or added to anything. Where a country levies one, it is not in your Wajub figures.
One row per payment, nothing more. A live payment that produced a record carries it as a tax
object on GET /payments/{id}: amount, taxable_amount, rate, name, country and
inclusive. A refund carries its reversal the same way. Totals and periods are read through the
report endpoint and the Dashboard, nowhere else.
No webhook. No event fires when a row is written or reversed.
Filing stays yours
Wajub computes a rate and keeps a ledger. It does not register you anywhere, does not file a return, and does not remit anything to an authority. Those obligations are yours, and the figures here are a starting point for your accountant rather than a filing.