A tax registration is a place where the seller is registered to collect sales tax, for a period of time. Automatic tax calculates tax only in states where the seller has a confirmed registration that is in effect on the sale's date. Each registration has a tax_registration_id beginning with trg_ and lives under the environment's tax connection, at /v1/tax-connection/registrations. Each sandbox keeps its own registrations, and they never carry over to live.
Registrations are individual resources, not an array you replace. You add, change, and remove one registration at a time, and the registration number is never sent back, so there is no list to resend. A state can have several registrations over time, such as one that ended and the one that replaced it. Listing and getting registrations requires settings.read. Creating, editing, and deleting them requires settings.write. Partner app install tokens can't call these routes.
Fields#
| Field | Description |
|---|---|
tax_registration_id | The registration's ID, beginning with trg_. |
country | US. Optional on create, and the only accepted value. |
state | A two-letter code from Accepted states. |
registration_number_last4 | The last four characters of the registration number. Flint never returns the full number. |
start_date | The first day the registration applies, such as 2026-03-01. On create, it can be up to 365 days in the future. |
end_date | The last day the registration applies, inclusive, such as 2026-12-31. null means the registration has no end date. |
status | pending, scheduled, active, ended, rejected, or removed. See Status. |
version | Increases whenever you change the registration. Send it as expected_version in the body on PATCH, or as the expected_version query parameter on DELETE. |
created_at, updated_at | When the registration was created and last changed. |
start_date and end_date are the first and last days the registration applies, both inclusive. Flint checks them against each sale's local date. status and the rules for these two fields use the UTC date.
registration_number is write-only. You send it on create and on PATCH, and Flint redacts it from request logs. Send 1 to 255 characters, exactly as the state issued it.
Status#
status is a closed set.
status | Meaning |
|---|---|
pending | Saved, but the tax account hasn't confirmed it. Flint doesn't calculate tax for the state under a pending registration. |
scheduled | The tax account confirmed the registration, and start_date is after today (UTC). It collects tax from start_date. |
active | The tax account confirmed the registration, start_date has arrived, and end_date hasn't passed or is null. Flint calculates tax for this state. |
ended | The tax account confirmed the registration, and end_date is before today (UTC). Flint no longer calculates tax under it. |
rejected | The tax account couldn't verify the number. Fix the number or delete the registration. |
removed | Only DELETE returns it, as the registration's final snapshot. The registration no longer exists. |
Flint works out scheduled, active, and ended from the UTC date each time you read a registration. When a date passes, the status changes without a write: version stays the same and Flint sends no webhook. Compare status with the dates instead of waiting for an event. A scheduled registration becomes active on its start_date, and an active registration becomes ended the day after its end_date.
Registrations you add before the connection is active stay pending until you connect, which syncs each one.
Which sales a registration covers#
Calculations use each sale's local date, not the UTC date, so the end of a registration follows the seller's calendar. A sale whose local date is from start_date through end_date, inclusive, collects tax. An order to a state with no registration in effect on the sale's date calculates zero tax: tax.status is calculated and pricing_amounts.tax_money is zero. This holds before a scheduled registration starts and after an ended one. An order calculated on a registration's last day and paid the next day is calculated again at payment, and gets zero tax.
Invoices that already carry issued tax, reports, and refunds don't change when a registration ends.
Accepted states#
country is US. state is one of the 47 jurisdictions Flint accepts: the 46 states below and DC. Delaware, Montana, New Hampshire, and Oregon have no sales tax, so they aren't accepted.
AL, AK, AZ, AR, CA, CO, CT, DC, FL, GA, HI, ID, IL, IN, IA, KS, KY, LA, ME, MD, MA, MI, MN, MS, MO, NE, NV, NJ, NM, NY, NC, ND, OH, OK, PA, RI, SC, SD, TN, TX, UT, VT, VA, WA, WV, WI, WY.
A state can have more than one registration, but their periods can't overlap. A registration with no end_date covers every day from its start_date onward. A request that would make two registrations in a state overlap, counting pending, scheduled, active, rejected, and ended registrations, returns 409 ALREADY_EXISTS. param is start_date or end_date, and details[0].current_resource names the registration it overlaps. Canadian registrations aren't supported, because automatic tax calculates US sales tax only.
Create a registration#
POST /v1/tax-connection/registrations takes state, registration_number, and start_date, and optionally country and end_date. start_date is required and can be up to 365 days after today (UTC). end_date must be on or after start_date and on or after today (UTC). An unsupported state, a start_date more than 365 days ahead, an end_date out of range, or a malformed number returns 400 INVALID_REQUEST with INVALID_VALUE and param naming the field. A successful create returns 201.
curl -X POST https://api.withflintpay.com/v1/tax-connection/registrations \
-H "Authorization: Bearer $FLINT_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: register-ca-cedar-and-stone" \
-d '{
"state": "CA",
"registration_number": "SR-GH-100234567",
"start_date": "2026-03-01"
}'
{
"data": {
"tax_registration_id": "trg_01KYB5A3V7E1S4JD8F2GM6HQ9X",
"country": "US",
"state": "CA",
"registration_number_last4": "4567",
"start_date": "2026-03-01",
"end_date": null,
"status": "active",
"version": 1793552714,
"created_at": "2026-11-01T17:05:12Z",
"updated_at": "2026-11-01T17:05:14Z"
}
}
Schedule a registration#
A start_date after today creates a scheduled registration. Use it when the seller registers in a new state before the registration takes effect. Flint doesn't calculate tax under it until start_date, and you can still set its end_date or delete it.
curl -X POST https://api.withflintpay.com/v1/tax-connection/registrations \
-H "Authorization: Bearer $FLINT_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: register-ny-cedar-and-stone" \
-d '{
"state": "NY",
"registration_number": "NYS-48210377",
"start_date": "2027-01-15"
}'
{
"data": {
"tax_registration_id": "trg_01KYB6D4H8J3K5M7Q9S2VXW0TA",
"country": "US",
"state": "NY",
"registration_number_last4": "0377",
"start_date": "2027-01-15",
"end_date": null,
"status": "scheduled",
"version": 1793555310,
"created_at": "2026-11-01T17:48:30Z",
"updated_at": "2026-11-01T17:48:30Z"
}
}
On a connection that isn't active, the same request saves a pending registration, and connect confirms it.
Before the connection is active#
While the tax connection isn't active, a create is saved in Flint only, as a pending registration. It never reaches the tax account and never creates the billed account. The first registration creates the connection record, so GET /v1/tax-connection starts returning a tax_connection_id. Add every state where the seller is registered, then connect.
On an active connection#
When the connection is active, the create syncs with the tax account during the request:
- The tax account accepts the number. The registration becomes
active, orscheduledwhenstart_dateis after today, and you get201. For anactiveregistration, Flint marks every open order that uses automatic tax, has calculated tax, and has no issued invoice as taxincomplete, because the new state changes where tax applies; update an order to recalculate it. Ascheduledregistration leaves open orders as they are, because it changes nothing about today's tax. - The tax account rejects the number. You get
400 INVALID_REQUESTwithINVALID_VALUEandparamregistration_number. Nothing changes: no registration is saved, the connection staysactive, and orders are untouched. Send the corrected number in a new create with a newIdempotency-Key; reusing the key replays the rejection. - The tax account can't be reached, or the outcome is unknown. You get
502 EXTERNAL_SERVICE_ERROR, or504 REQUEST_TIMEOUTwhen the tax service doesn't respond in time. The registration stayspendingand the connection staysactive. Orders to the state calculate zero tax until the registration is confirmed. Retry the same request with the sameIdempotency-Key; Flint resumes and doesn't create a second entry in the tax account.
If Flint can't remove a rejected number from the tax account, the registration stays rejected and the connection becomes attention_required with status_reason registration_rejected. Delete the registration, then connect again.
If the create response is lost#
Without the original Idempotency-Key, a second create for the same period returns 409 ALREADY_EXISTS. List the registrations for the state and match the start_date you sent:
curl "https://api.withflintpay.com/v1/tax-connection/registrations?state=NY" \
-H "Authorization: Bearer $FLINT_SECRET_KEY"
An active or scheduled match means the create succeeded. A pending match on an active connection is one the sync didn't finish: delete it, then create it again. If that delete returns 502, Flint hasn't yet confirmed whether the unfinished create reached the tax account; retry the delete with the same Idempotency-Key. A pending match on a connection that isn't active is the normal saved state, and connect syncs it.
List and get#
GET /v1/tax-connection/registrations returns registrations ordered by state and then tax_registration_id, both ascending. Filter with status, which takes one or more values, and with state, which takes one or more two-letter codes and matches exactly. Combine them to find the registration in effect for a state, such as state=CA&status=active. Removed registrations never appear. page_size is 1 to 100 and defaults to 100; pass next_page_token as page_token if a response includes one.
{
"data": [
{
"tax_registration_id": "trg_01KYB5A3V7E1S4JD8F2GM6HQ9X",
"country": "US",
"state": "CA",
"registration_number_last4": "4567",
"start_date": "2026-03-01",
"end_date": null,
"status": "active",
"version": 1793552714,
"created_at": "2026-11-01T17:05:12Z",
"updated_at": "2026-11-01T17:05:14Z"
},
{
"tax_registration_id": "trg_01KYB5C9N0P2R5T8WZ3XQ6V1HB",
"country": "US",
"state": "WA",
"registration_number_last4": "0098",
"start_date": "2026-05-15",
"end_date": null,
"status": "pending",
"version": 1793552980,
"created_at": "2026-11-01T17:09:40Z",
"updated_at": "2026-11-01T17:09:40Z"
}
]
}
GET /v1/tax-connection/registrations/{tax_registration_id} returns one registration. An ID from another environment, or one you deleted, returns 404 RESOURCE_NOT_FOUND.
Edit a registration#
PATCH /v1/tax-connection/registrations/{tax_registration_id} takes registration_number, start_date, end_date, and expected_version. Send at least one field besides expected_version; an empty body returns 400 INVALID_REQUEST with REQUIRED and param body. A stale expected_version returns 409 VERSION_CONFLICT with details[0].current_version. Edits are saved in Flint only. They don't contact the tax account. Changing a rejected registration's registration_number or start_date makes it pending; connect then syncs it.
What you can change depends on the registration's status:
| Field | pending or rejected | scheduled | active | ended |
|---|---|---|---|---|
registration_number | Yes | No | No | No |
start_date | Yes | No | No | No |
end_date | Yes | Yes | Yes | No |
end_date must be on or after start_date and on or after today (UTC). Send null to remove the end date before the registration has ended. An out-of-range date returns 400 INVALID_REQUEST with INVALID_VALUE and param end_date. An edit that would make the registration overlap another in the state returns 409 ALREADY_EXISTS.
If a pending or rejected registration may already be in the tax account, for example after an interrupted setup, its start_date can't be changed: the request returns 409 ACTION_NOT_ALLOWED with field_locked and param start_date. Delete the registration and create it again.
While the connection is active, a pending or rejected registration's number and start_date can't be edited: the request returns 409 ACTION_NOT_ALLOWED with unsupported_state, and details[0].resource_type is tax_connection. Delete the registration and create it again. end_date edits on scheduled and active registrations work whether or not the connection is active.
A field the status doesn't allow returns 409 ACTION_NOT_ALLOWED with details[0].reason field_locked. details[0].param names the field and current_status is the registration's status. Any edit to an ended registration returns 409 ACTION_NOT_ALLOWED with unsupported_state.
Set an end date#
Send end_date to stop collecting tax in a state after a given day. The registration stays active through that day and becomes ended the day after:
curl -X PATCH https://api.withflintpay.com/v1/tax-connection/registrations/trg_01KYB5A3V7E1S4JD8F2GM6HQ9X \
-H "Authorization: Bearer $FLINT_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"end_date": "2026-12-31",
"expected_version": 1793552714
}'
{
"data": {
"tax_registration_id": "trg_01KYB5A3V7E1S4JD8F2GM6HQ9X",
"country": "US",
"state": "CA",
"registration_number_last4": "4567",
"start_date": "2026-03-01",
"end_date": "2026-12-31",
"status": "active",
"version": 1793554340,
"created_at": "2026-11-01T17:05:12Z",
"updated_at": "2026-11-01T17:32:20Z"
}
}
Setting or changing an end date doesn't mark open orders as tax incomplete. Flint applies the end date when it calculates each sale, so orders after the last day get zero tax.
If a state has no later registration, tax stops there after the end date. Create the next registration before then if the seller is still registered.
Remove an end date#
Send end_date as null to make the registration open-ended again. This works until the registration has ended; an ended registration can't be edited.
curl -X PATCH https://api.withflintpay.com/v1/tax-connection/registrations/trg_01KYB5A3V7E1S4JD8F2GM6HQ9X \
-H "Authorization: Bearer $FLINT_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"end_date": null,
"expected_version": 1793554340
}'
{
"data": {
"tax_registration_id": "trg_01KYB5A3V7E1S4JD8F2GM6HQ9X",
"country": "US",
"state": "CA",
"registration_number_last4": "4567",
"start_date": "2026-03-01",
"end_date": null,
"status": "active",
"version": 1793554802,
"created_at": "2026-11-01T17:05:12Z",
"updated_at": "2026-11-01T17:40:02Z"
}
}
Change a pending registration#
While a registration is pending or rejected and the connection isn't active, you can also correct its number or start_date:
curl -X PATCH https://api.withflintpay.com/v1/tax-connection/registrations/trg_01KYB5C9N0P2R5T8WZ3XQ6V1HB \
-H "Authorization: Bearer $FLINT_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"registration_number": "602-418-337",
"expected_version": 1793552980
}'
Change a registration number#
A scheduled or active registration keeps its number and start date. To switch to a new number, end the old registration, then create the new one starting the next day:
PATCHthe old registration withend_dateset to the last day the old number applies. It must be today (UTC) or later.POSTa new registration for the same state with the newregistration_numberand astart_dateone day after thatend_date.
curl -X PATCH https://api.withflintpay.com/v1/tax-connection/registrations/trg_01KYB5A3V7E1S4JD8F2GM6HQ9X \
-H "Authorization: Bearer $FLINT_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: end-ca-registration-2026" \
-d '{
"end_date": "2026-12-31",
"expected_version": 1793552714
}'
curl -X POST https://api.withflintpay.com/v1/tax-connection/registrations \
-H "Authorization: Bearer $FLINT_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: register-ca-new-number-2027" \
-d '{
"state": "CA",
"registration_number": "SR-GH-100998877",
"start_date": "2027-01-01"
}'
{
"data": {
"tax_registration_id": "trg_01KYB6F2R7T9W1Y3Z5B8CDE0GH",
"country": "US",
"state": "CA",
"registration_number_last4": "8877",
"start_date": "2027-01-01",
"end_date": null,
"status": "scheduled",
"version": 1793555700,
"created_at": "2026-11-01T17:55:00Z",
"updated_at": "2026-11-01T17:55:00Z"
}
}
Sales through December 31 are calculated under the old registration, and sales from January 1 under the new one. The new registration becomes active on its start_date. The old one stays in the list as ended. It can't be edited or deleted.
If the create times out or returns a 5xx after you set the end date, retry it with the same Idempotency-Key. If it returns a 4xx, fix the request and send it with a new key. To keep the old registration instead, PATCH its end_date to null before it ends. If you leave a gap between the old end_date and the new start_date, orders in those days calculate zero tax. A start_date that overlaps the old registration returns 409 ALREADY_EXISTS.
Delete a registration#
DELETE /v1/tax-connection/registrations/{tax_registration_id} removes a pending, rejected, or scheduled registration and returns its final snapshot with status removed. A GET afterward returns 404. If the tax account might hold a copy of a pending or rejected registration, Flint removes that copy first and marks every open order that uses automatic tax, has calculated tax, and has no issued invoice as tax incomplete, because the state may have been taxed. Deleting a scheduled registration removes its copy from the tax account but leaves open orders as they are, because Flint never calculated tax under it. If the tax service fails, or Flint can't yet confirm whether an unfinished create reached the tax account, the delete returns 502 EXTERNAL_SERVICE_ERROR (or 504 REQUEST_TIMEOUT when the tax service doesn't respond in time) and removes nothing; retry with the same Idempotency-Key. Add ?expected_version= with the registration's version to delete it only if it hasn't changed since you read it.
curl -X DELETE https://api.withflintpay.com/v1/tax-connection/registrations/trg_01KYB5C9N0P2R5T8WZ3XQ6V1HB \
-H "Authorization: Bearer $FLINT_SECRET_KEY" \
-H "Idempotency-Key: delete-wa-cedar-and-stone"
{
"data": {
"tax_registration_id": "trg_01KYB5C9N0P2R5T8WZ3XQ6V1HB",
"country": "US",
"state": "WA",
"registration_number_last4": "0098",
"start_date": "2026-05-15",
"end_date": null,
"status": "removed",
"version": 1793553605,
"created_at": "2026-11-01T17:09:40Z",
"updated_at": "2026-11-01T17:20:05Z"
}
}
An active or ended registration can't be deleted: the request returns 409 ACTION_NOT_ALLOWED with unsupported_state and current_status set to its status. To stop collecting in a state, set an end date instead.
Webhooks#
Registrations have no events of their own. Every create, edit, and delete, including the first registration and the last deletion, sends tax_connection.updated; see the tax connection webhook. After you receive one, list the registrations again. A registration changing from scheduled to active, or from active to ended, because a date passed sends no event and doesn't change version.
Errors#
Registration writes follow the connection's state. While a connect is running they return 409 OPERATION_IN_PROGRESS. When the connection's status_reason is business_details_changed or support_required, or its status is disabled, they return 409 ACTION_NOT_ALLOWED and Flint support has to act. A PATCH that only sets or clears end_date on a scheduled or active registration is the exception: it works in every connection state, so you can always stop a registration. See Status reasons.
