DOCS

Tax exemptions

Tax exemptions

Sync US sales tax exemption certificates to a customer profile.

If you sell to resellers, government agencies, or nonprofits, those buyers hold exemption certificates that exempt them from sales tax in specific states. Zonos stores those certificates against a customer profile so an exempt buyer can be recognized at checkout.

Exemptions are recorded per jurisdiction. A customer exempt in South Carolina is not automatically exempt in Texas, so each state the customer holds a certificate for is a separate record with its own dates and certificate number.

Exemptions attach to an existing customer, so syncing is two calls: create the customer, then sync their certificates. Both are keyed on your own customer ID — the same customerId you use elsewhere in Checkout. Zonos never requires you to store an internal ID.

This feature is available for custom API integrations only.

Exemptions are not yet applied to landed cost quotes

You can sync and manage exemptions today, and the records are stored against the customer profile. Deducting an exemption from the tax on a landed cost is coming soon, so a synced exemption does not change the tax a shopper is quoted yet. Syncing now means your certificates are already in place when it does.

Create or update the customer 

checkoutCustomerUpsert creates a customer profile, or updates it if one already exists for that customerId. Unlike checkoutCustomerProfileAuthenticate, this does not require the shopper to be present, so you can provision your customer list ahead of time. See create or update a profile without a shopper for the full field behavior.

1mutation checkoutCustomerUpsert($input: CheckoutCustomerProfileInput!) {
2 checkoutCustomerUpsert(input: $input) {
3 customerId
4 email
5 name
6 phone
7 }
8}

Because it matches on customerId, calling it repeatedly updates the same profile rather than creating duplicates. It is safe to run across your whole customer list on every sync.

Sync tax exemptions 

checkoutCustomerTaxExemptionsSync accepts several customers at once. Each entry replaces that customer's full set of exemptions.

1mutation checkoutCustomerTaxExemptionsSync(
2$input: [CheckoutCustomerTaxExemptionSyncInput!]!
3) {
4 checkoutCustomerTaxExemptionsSync(input: $input) {
5 customerId
6 accepted {
7 id
8 countryCode
9 administrativeArea
10 effectiveAt
11 expiresAt
12 exemptionReason
13 }
14 rejected {
15 code
16 message
17 administrativeArea
18 effectiveAt
19 }
20 }
21}

An omitted expiresAt means the certificate does not expire. An omitted exemptionReason defaults to UNSPECIFIED.

How syncing works 

Three rules govern every sync.

The list is authoritative. taxExemptions is the customer's complete set, not a list of changes. Any exemption already on record that is missing from the list is removed — that is how a withdrawn certificate stops being honored. Sending a partial list silently removes everything it leaves out.

Every record is an exemption. There is no way to record that a customer is not exempt somewhere — see the note below.

Removing all exemptions is an empty list. To clear a customer's certificates, send them with "taxExemptions": []. Leaving the customer out of the payload entirely leaves their existing records untouched.

Send only jurisdictions the customer is exempt in

Zonos has no "not exempt" record — a jurisdiction is either in the list or it isn't. If your system stores exempt and non-exempt jurisdictions together, filter to the exempt ones before syncing. A non-exempt record is indistinguishable from a real certificate, so it is accepted rather than rejected, and the customer will be treated as exempt in that state.

Exemption reasons 

exemptionReason describes why the customer is exempt. It is optional and defaults to UNSPECIFIED, but supplying it is worth the effort — see below.

ValueApplies to
RESALEGoods purchased to resell rather than consume
FEDERAL_GOVERNMENTA US federal agency or department
STATE_LOCAL_GOVERNMENTA state agency, county, municipality, or school district
TRIBAL_GOVERNMENTA federally recognized tribe or tribal member
CHARITABLEA charitable nonprofit
RELIGIOUS_ORGANIZATIONA church or other religious organization
EDUCATIONAL_ORGANIZATIONA school or university
DIRECT_PAYA buyer who holds a direct pay permit and remits tax themselves
OTHERAnything else, including foreign diplomat, agricultural production, industrial production, and direct mail
UNSPECIFIEDNo reason supplied

Reasons fall into two groups, and the difference matters. Entity-based reasons — government, charitable, religious, educational — exempt the buyer no matter what they purchase. Use-based reasons, RESALE above all, only cover qualifying goods: a resale certificate covers inventory the buyer will resell, not the office furniture on the same order.

Without a reason, Zonos cannot tell the two apart and can only exempt whole orders, which is hardest to defend for resale certificates. If most of your exemptions are resale, sending RESALE as a default with exceptions listed individually is usually much less work than classifying every customer.

Exemption reference 

exemptionReference is the number printed on the customer's exemption paperwork. Depending on the state and the type of exemption, that may be a resale or seller's permit number, a state exemption certificate number, a direct pay permit number, or a federal tax ID.

It is required on every record. Store and send it exactly as it appears on the certificate — formats vary widely by jurisdiction (SR EAA 12-345678, 85-8012345678C-9, 12-3456789), and Zonos preserves the value as sent apart from trimming surrounding whitespace. Do not change capitalization or strip hyphens and spaces.

For privacy, exemptionReference can be sent but is not returned when reading exemptions back, since it may contain a federal tax ID.

Rejected records 

Records are validated one at a time. A rejected record is reported in rejected and does not fail the rest of the batch, nor does it disturb the exemption already on record for that jurisdiction.

CodeCause
UNKNOWN_CUSTOMERNo customer matches customerId. Create the customer first
UNKNOWN_JURISDICTIONadministrativeArea is not a recognized US state, district, or territory
INVALID_DATE_RANGEexpiresAt is not after effectiveAt
MISSING_EXEMPTION_REFERENCEexemptionReference is empty
DUPLICATE_JURISDICTIONTwo records in one payload share a country, area, and effective date. The first is kept

Unknown customers are rejected rather than created, so a mistyped customerId surfaces in the response instead of creating a profile that never matches a real buyer.

Only US administrative areas are validated. Subdivisions of other countries are accepted as sent.

Read back and remove 

Read a customer's exemptions to confirm a sync landed:

1query checkoutCustomerTaxExemptions($customerId: String!) {
2 checkoutCustomerTaxExemptions(customerId: $customerId) {
3 countryCode
4 administrativeArea
5 effectiveAt
6 expiresAt
7 exemptionReason
8 }
9}

To remove every exemption for a customer — when they close their account, for example — use checkoutCustomerTaxExemptionsDelete. It returns SUCCESS whether or not the customer had any exemptions, so it is safe to call more than once.

1mutation checkoutCustomerTaxExemptionsDelete($customerId: String!) {
2 checkoutCustomerTaxExemptionsDelete(customerId: $customerId)
3}
Book a demo

Was this page helpful?