Sales Tax Calculator API
Create an immutable sales tax calculation from seller, customer, item-classification, location, currency, and billing facts. Each response gives your application a stable outcome and the amounts it may use.
https://api.salestaxcalculatorapi.comCall the API from trusted server code. Never put a secret API key in browser or mobile code.
/v1/calculationsCreate one immutable sales tax calculation.
Send JSON with a bearer key and an idempotency key tied to the business operation. The examples set connection and response timeouts and stop when the API returns a non-determinate outcome.
/v1/calculationscurl \ --request POST \ --url "https://api.salestaxcalculatorapi.com/v1/calculations" \ --connect-timeout 5 \ --max-time 15 \ --header "Authorization: Bearer $STCA_API_KEY" \ --header "Content-Type: application/json" \ --header "Idempotency-Key: checkout-order-1001" \ --data '{30 collapsed lines
"reference": "order-1001", "transaction_date": "2026-08-29", "currency": "CAD", "tax_behavior": "exclusive", "billing_event": "subscription_start", "seller": { "country": "CA", "channel_role": "direct_legal_supplier", "registrations": [ { "country": "CA", "state": "ON", "type": "gst_hst", "effective_from": "2026-01-01" } ] }, "customer": { "type": "consumer", "address": { "country": "CA", "state": "ON", "postal_code": "M5V 2T6" } }, "lines": [ { "reference": "subscription", "amount": "100.00", "quantity": "1", "tax_code": "saas" } ] }'{ "id": "calc_01J6A3S8Z6K4M6T2Y2W9M5X8Q0", "object": "calculation", "reference": "order-1001", "outcome": "calculated", "currency": "CAD", "subtotal": "100.00", "taxable_amount": "100.00", "tax": "13.00", "total": "113.00", "lines": [13 collapsed lines
{ "id": "line_01J6A3T26X8BS4Y8XJKZ0H8F3P", "reference": "subscription", "outcome": "calculated", "subtotal": "100.00", "taxable_amount": "100.00", "tax": "13.00", "total": "113.00", "explanation": "Tax was calculated for this sale." } ], "explanation": "Tax was calculated for this sale.", "request_id": "req_01J6A3RZ1HT2K3W2X8R7P1J4C9", "created_at": "2026-08-29T12:00:00Z"}Example sales tax calculation
This example is a CAD 100.00 tax-exclusive SaaS subscription sold directly to a consumer in Ontario by a seller with an effective Ontario GST/HST registration. The response applies 13% HST: CAD 100.00 subtotal + CAD 13.00 tax = CAD 113.00 total.
The example rate matches the Canada Revenue Agency GST/HST rate table. It demonstrates the request and response shape. Another transaction can return a different amount or outcome.
Sales tax calculation request fields
Unknown fields and JSON numbers for money are rejected. Use uppercase country, subdivision, and currency codes. Use lowercase API enum and tax-code values.
| Field | Use | Meaning |
|---|---|---|
reference | Recommended | Your order, invoice, or cart reference. Returned with the sales tax calculation. |
transaction_date | Recommended | Commercial date in YYYY-MM-DD form. It defaults to the current UTC date, so send it explicitly when results must be reproducible. |
currency | Required | Three-letter uppercase ISO 4217 code. All money values are decimal strings in this currency. |
tax_behavior | Required | Use exclusive when line amounts exclude tax. Use inclusive when line amounts already include tax. |
billing_event | Required | The commercial event, such as one_time_charge, subscription_start, subscription_renewal, or metered_usage. |
seller | Required | Seller country, channel role, and effective-dated tax registrations that apply to this sale. |
customer | Required | Customer type and location. Add tax IDs or independent location evidence only when they apply. |
ship_from / ship_to | Conditional | Supply-chain locations when shipping facts affect the transaction. |
lines | Required | Between 1 and 100 lines. Each line needs a unique reference, total line amount, and tax code. Quantity defaults to 1. |
amount is the total monetary amount for the line, not a unit price. quantity records how many units that total represents and supports proportional quantity adjustments later.Sales tax calculation response fields
A created sales tax calculation returns HTTP 201 even when its tax outcome is review_required or unsupported. Check outcome before using tax or total.
| Field | How to use it |
|---|---|
outcome | The decision for the complete sales tax calculation. Branch on this before using any amount. |
subtotal | Tax-exclusive amount represented by the response. |
taxable_amount | Amount to which tax was applied. |
tax | Calculated tax amount. This is 0.00 for non-determinate and valid zero-tax outcomes. |
total | Subtotal plus tax for exclusive pricing, or the submitted gross amount for inclusive pricing. |
lines | Per-line outcome and final amounts. Keep these with the order for later adjustments. |
explanation | Customer-readable reason for the returned outcome. |
id / request_id | Stable identifiers for retrieval, logs, and support. |
created_at | UTC timestamp at which the immutable sales tax calculation was created. |
For tax-exclusive pricing, the submitted line amount is the subtotal and tax is added. For tax-inclusive pricing, the submitted line amount is the total and the response separates its subtotal and tax. Use the returned decimal strings instead of recalculating from a displayed rate.
Sales tax calculation outcomes
HTTP 201The HTTP status says the resource was created. The outcome says whether the returned amounts are a final tax decision.
| Outcome | Meaning | Application action |
|---|---|---|
calculated | Tax was calculated from the supplied seller and transaction facts. | Use the returned tax and total. |
not_taxable | The supplied item is not taxable for this transaction. | Use the returned zero-tax result. |
not_obligated | The seller is not the party required to collect tax. | Use the returned zero-tax result. |
reverse_charge_or_self_assess | The customer is responsible for the tax treatment. | Use the returned result and preserve the explanation. |
exempt | Accepted evidence supports an exemption. | Use the returned zero-tax result. |
no_general_tax | The jurisdiction has no general transaction tax for this sale. | Use the returned zero-tax result. |
review_required | The supplied facts cannot support a final answer. | Stop automatic tax handling and review the transaction. |
unsupported | This exact combination is not currently supported. | Do not infer a rate or treat 0.00 as a tax decision. |
Production handling
- Keep credentials server-side. Send the bearer key only from infrastructure you control.
- Make the request reproducible. Send the commercial transaction date, a stable reference, effective seller registrations, and the location and item-classification facts available at checkout.
- Tie idempotency to the operation. Reuse the same key and body when retrying the same order. Create a new key for a new operation.
- Branch on the top-level outcome. Treat
review_requiredandunsupportedas non-determinate even when individual lines contain amounts. - Store the response. Keep the sales tax calculation ID, request ID, line IDs, outcome, amounts, and explanation with the order.
- Use returned amounts. Use the returned decimal strings to charge, display, finalize, and adjust amounts. Do not rebuild tax from rounded display values.
- Retry deliberately. Retry only retryable failures, honor the supplied delay, and preserve the original idempotency key and request body.
Errors and retries
Errors use RFC 9457 application/problem+json. Branch on the stable lowercase code, retain request_id, and inspect retryable. Field errors include a JSON Pointer.
| HTTP | Typical code | Client action |
|---|---|---|
| 400 | invalid_request / unknown_field / invalid_idempotency_key | Correct the listed request fields or header. |
| 401 | invalid_api_key | Use an active account API key. |
| 403 | forbidden | Check the account entitlement and API-key permissions. |
| 404 | resource_not_found | Check the resource ID and account access. |
| 409 | idempotency_conflict / request_in_progress | Reuse the original request or retry after the indicated delay. |
| 413 | request_too_large | Reduce the request or batch size. |
| 422 | unsupported_currency / calculation_not_finalizable | Change the unsupported value or resolve the resource state. |
| 429 | rate_limit_exceeded | Wait for Retry-After, then retry. This response does not consume an API call. |
| 429 | usage_cap_reached | Review or change the account usage limit before retrying. |
| 503 | tax_data_ambiguous | Retry only when retryable is true. |
When a retry is allowed, wait for Retry-After or retry_after_seconds when present and resend the identical body with the same idempotency key. A different body with that key returns 409 idempotency_conflict.
Authentication
Send an stca_ API key, shown only once when created, as a bearer token. Your API key continues to work when you move from evaluation to a paid plan.
Authorization: Bearer stca_••••••••Send every request to the base URL shown above. You do not need tenant, mode, or environment headers.
Idempotency
Every create request needs an Idempotency-Key containing 8 to 255 safe ASCII characters and matching [A-Za-z0-9][A-Za-z0-9_.:-]{7,254}.
Repeating the same canonical request with the same key returns the original resource and Idempotent-Replayed: true. JSON whitespace or property order does not create a conflict.
Sales tax calculation audit details
Add ?expand=audit when your application needs the dated coverage basis, effective period, jurisdiction components, rates, taxable amounts, tax amounts, and evidence status returned for the sales tax calculation.
POST /v1/calculations?expand=auditThe expansion contains customer-facing sales tax calculation evidence. Store it with the result when your invoice, support, or reconciliation workflow needs those details.
API endpoints
All customer resources are scoped to the account authenticated by the bearer key.
POST/v1/calculationsCreate a sales tax calculation
GET/v1/calculations/{calculation_id}Retrieve a sales tax calculation
POST/v1/transactionsCreate a transaction
GET/v1/transactions/{transaction_id}Retrieve a transaction
POST/v1/transactions/{transaction_id}/adjustmentsCreate an adjustment
GET/v1/transactions/{transaction_id}/adjustmentsList transaction adjustments
GET/v1/transactions/{transaction_id}/adjustments/{adjustment_id}Retrieve an adjustment
POST/v1/calculation-batchesCreate a sales tax calculation batch
GET/v1/calculation-batches/{batch_id}Retrieve a sales tax calculation batch
GET/v1/coverageCheck qualified coverage
Coverage
Use GET /v1/coverage to check a specific country, region, tax code, transaction type, customer type, and date without creating a sales tax calculation. A sales tax calculation request does not require a preceding coverage request and always returns its own outcome.
The API calculates and records supported indirect-tax results. It does not file returns, remit tax, register businesses, or provide legal advice. Unsupported or incomplete combinations fail closed without inventing a tax amount.
OpenAPI specification
The OpenAPI 3.1.2 document defines request schemas, responses, errors, examples, and compatibility behavior for the public API.
