Nexus Management

Record the physical locations a self-managed merchant operates from, so Ziptax knows where they collect and how their sales are sourced.

Available onProEnterprise

Nexus management lets your platform record each self-managed merchant’s physical locations on Ziptax. Those locations are what establish the merchant’s nexus, and nexus is what decides whether a sale is sourced at its origin or its destination — so this is the data a self-managed cart calculation depends on.

This applies to self-managed merchants only. A TaxCloud-connected merchant’s nexus is held in TaxCloud, where TaxCloud manages it as part of end-to-end compliance; every endpoint on this page returns 403 for one.

Why nexus matters

A merchant must collect sales tax in every state where it has nexus, a connection to the state significant enough to create a tax obligation. The footprint you record does two jobs:

  1. It defines where the merchant collects. Ziptax uses it as the record of the merchant’s collection obligations.
  2. It drives correct calculation. Some states source sales tax to the ship-from location (origin-based) rather than the ship-to location (destination-based), so calculating the right rate depends on knowing where the merchant ships from.

Nexus comes in two kinds:

KindHow it arisesRecorded how
Physical presenceAn office, store, warehouse, inventory, employee, or other in-state presenceDeclared by you, through the endpoints on this page
Economic nexusSales into a state cross that state’s sales or transaction thresholdDerived from sales activity, not declared. See economic nexus below

See Collection Requirements and Nexus for background on the legal concepts, and Economic Thresholds for how state thresholds work.

The location object

Record every place the merchant has a physical presence in the US: offices, stores, warehouses, inventory (including inventory held in fulfillment networks such as FBA), employees, property, and temporary presence such as trade shows.

Only locationType and address are required. Everything else is optional and defaulted.

FieldTypeRequiredDescription
locationTypestringYesWhat kind of presence this is. One of the seven types.
addressstringYesThe location’s US address, as a single line. Max 255 characters. Geocoded on write.
registeredbooleanNoWhether the merchant is registered to collect sales tax in this location’s state. Defaults to false.
isFulfillmentOriginbooleanNoWhether goods actually ship from here. This is the field origin-sourcing consults. Defaults by locationType.
namestringNoYour own label, for example TestCo Texas Distribution Center. Max 255 characters. Returned as-is and never used in a calculation.
referenceIdstringNoThe ID you use for this location in your own system, for example warehouse-123. Max 255 characters.
locationIdstringServer-issued on create and returned on every read, for example P-6dc371de-00a4-44bf-8a88-2bcab2f15041. Use it to update and delete.

Location types

locationTypeCovers
officeCorporate, administrative, or branch offices
storeRetail storefronts
warehouseStorage facilities holding the merchant’s inventory
fulfillmentThird-party fulfillment centers, including marketplace networks such as FBA
personnelEmployees or contractors working in a state
propertyInventory or equipment held in a state
temporaryShort-term presence such as a trade show

Fulfillment origin

isFulfillmentOrigin is the field origin-sourcing actually reads, and when you omit it Ziptax infers it from locationType:

locationTypeDefault isFulfillmentOrigin
warehouse, fulfillment, storetrue
office, personnel, property, temporaryfalse

Set isFulfillmentOrigin explicitly for anything that does not match the default — an office that also ships, or a warehouse that only holds stock and never ships. Leaving it to the default in those cases changes which address an origin-sourced sale is calculated from.

How addresses are handled

You send the address the way your merchant gave it to you, as a single line. Ziptax geocodes it on write and returns the normalized result, so the address you read back will not be byte-identical to the one you sent:

DirectionValue
Sent1401 Lavaca St Austin TX 78701
Returned1401 Lavaca St, Austin, TX 78701-1634, United States

US addresses only. An address that cannot be resolved to a state is rejected with 422 rather than stored. Match on locationId or referenceId rather than on the address string.

Create locations

POST
/merchant/nexus/create
1curl -X POST https://api.zip-tax.com/merchant/nexus/create \
2 -H "X-API-KEY: <apiKey>" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "locations": [
6 {
7 "address": "1401 Lavaca St Austin TX 78701",
8 "locationType": "office"
9 }
10 ],
11 "merchantId": "merchantId"
12}'

create takes an array, so you can register a merchant’s whole footprint in one call. Up to 25 locations per call — each one is geocoded as it is written, which is what bounds the batch.

cURL
$curl -X POST "https://api.zip-tax.com/merchant/nexus/create" \
> -H "X-API-KEY: YOUR_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "merchantId": "dc835fea-b9fb-4f5e-a253-b896455d673f",
> "locations": [{
> "locationType": "warehouse",
> "name": "TestCo Texas Distribution Center",
> "address": "1401 Lavaca St Austin TX 78701",
> "registered": true,
> "referenceId": "warehouse-123"
> }]
> }'

The response returns the stored locations in the order submitted, each with its locationId and normalized address:

1{
2 "merchantId": "dc835fea-b9fb-4f5e-a253-b896455d673f",
3 "locations": [{
4 "locationId": "P-6dc371de-00a4-44bf-8a88-2bcab2f15041",
5 "locationType": "warehouse",
6 "name": "TestCo Texas Distribution Center",
7 "address": "1401 Lavaca St, Austin, TX 78701-1634, United States",
8 "registered": true,
9 "isFulfillmentOrigin": true,
10 "referenceId": "warehouse-123"
11 }]
12}

Persist the locationId values. They are the handle for every later update or delete.

The batch is all-or-nothing

If any address in the request cannot be resolved to a US state, the whole request is rejected with 422 and nothing is stored. That is deliberate: it means a retry cannot duplicate the locations that would otherwise have succeeded, so you can fix the bad address and resend the same payload safely.

Address resolution for the whole request is budgeted at 10 seconds. A batch that exceeds it returns 504 and stores nothing — but geocoding that had already completed is still billed, because the lookups were still performed. Send fewer locations per call if you hit this.

List the footprint

POST
/merchant/nexus/list
1curl -X POST https://api.zip-tax.com/merchant/nexus/list \
2 -H "X-API-KEY: <apiKey>" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "merchantId": "merchantId"
6}'

Send merchantId alone to get the merchant’s whole footprint. Deleted locations are not included, and an empty array means no physical nexus is being tracked for that merchant.

cURL
$curl -X POST "https://api.zip-tax.com/merchant/nexus/list" \
> -H "X-API-KEY: YOUR_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "merchantId": "dc835fea-b9fb-4f5e-a253-b896455d673f"
> }'
1{
2 "merchantId": "dc835fea-b9fb-4f5e-a253-b896455d673f",
3 "locations": [{
4 "locationId": "P-6dc371de-00a4-44bf-8a88-2bcab2f15041",
5 "locationType": "warehouse",
6 "name": "TestCo Texas Distribution Center",
7 "address": "1401 Lavaca St, Austin, TX 78701-1634, United States",
8 "registered": true,
9 "isFulfillmentOrigin": true,
10 "referenceId": "warehouse-123"
11 }]
12}

The optional nexusType filter accepts physical or economic. Omit it to return every kind.

Update a location

POST
/merchant/nexus/update
1curl -X POST https://api.zip-tax.com/merchant/nexus/update \
2 -H "X-API-KEY: <apiKey>" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "location": {
6 "address": "1401 Lavaca St Austin TX 78701",
7 "locationType": "office"
8 },
9 "locationId": "6dc371de-00a4-44bf-8a88-2bcab2f15041",
10 "merchantId": "merchantId"
11}'

Identify the location with locationId at the top level, and send its new contents in a location object.

location is a full replacement, not a patch. Every field in it is written, so send the current value for anything you do not want cleared — omitting name or referenceId empties them, and omitting registered resets it to false. Read the location first if you do not already hold its current values.

cURL
$curl -X POST "https://api.zip-tax.com/merchant/nexus/update" \
> -H "X-API-KEY: YOUR_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "merchantId": "dc835fea-b9fb-4f5e-a253-b896455d673f",
> "locationId": "P-6dc371de-00a4-44bf-8a88-2bcab2f15041",
> "location": {
> "locationType": "warehouse",
> "name": "TestCo Texas Distribution Center",
> "address": "1401 Lavaca St Austin TX 78701",
> "registered": true,
> "referenceId": "warehouse-123"
> }
> }'

The response returns the stored location as a single location object, not an array:

1{
2 "merchantId": "dc835fea-b9fb-4f5e-a253-b896455d673f",
3 "location": {
4 "locationId": "P-6dc371de-00a4-44bf-8a88-2bcab2f15041",
5 "locationType": "warehouse",
6 "name": "TestCo Texas Distribution Center",
7 "address": "1401 Lavaca St, Austin, TX 78701-1634, United States",
8 "registered": true,
9 "isFulfillmentOrigin": true,
10 "referenceId": "warehouse-123"
11 }
12}

Two things to expect. The address is geocoded again, so the normalized result can change even when you send the same string — and a location can be moved to a different state this way. And a locationId that has already been deleted returns 404.

The most common update is flipping registered once a merchant completes a state registration. Because the block is a full replacement, send the location’s other current values alongside it.

Delete a location

POST
/merchant/nexus/delete
1curl -X POST https://api.zip-tax.com/merchant/nexus/delete \
2 -H "X-API-KEY: <apiKey>" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "locationId": "6dc371de-00a4-44bf-8a88-2bcab2f15041",
6 "merchantId": "merchantId"
7}'
cURL
$curl -X POST "https://api.zip-tax.com/merchant/nexus/delete" \
> -H "X-API-KEY: YOUR_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "merchantId": "dc835fea-b9fb-4f5e-a253-b896455d673f",
> "locationId": "P-6dc371de-00a4-44bf-8a88-2bcab2f15041"
> }'
1{
2 "merchantId": "dc835fea-b9fb-4f5e-a253-b896455d673f",
3 "locationId": "P-6dc371de-00a4-44bf-8a88-2bcab2f15041",
4 "message": "location removed"
5}

The location stops appearing in list immediately and no longer contributes to the merchant’s nexus. It is retained internally so past filings keep their basis. Deleting a location that is already gone returns 404.

There is no minimum. Removing a merchant’s last location is allowed — it simply means no physical nexus is tracked for them. Deleting a location that still reflects a real presence does not end the merchant’s obligation in that state, so keep the footprint current.

Economic nexus

Economic nexus is derived from a merchant’s sales activity rather than declared, so it cannot be created through these endpoints. nexusType on create accepts only physical; sending economic is rejected rather than silently stored as physical.

On list, nexusType: "economic" is accepted and currently returns an empty list, because economic nexus is not yet tracked.

Ziptax publishes the per-state threshold reference data, but does not monitor a merchant’s sales against it. See Economic Thresholds for how the thresholds are constructed and where to find the data.

Errors

StatusMeaning
400Malformed request body.
401Missing or invalid API key.
403The merchant is TaxCloud-connected. These endpoints are for self-managed merchants only.
404The locationId does not exist, or has already been deleted.
422An address could not be resolved to a US state. On create, nothing in the batch is stored.
429Rate limit exceeded. See Rate Limiting & Errors.
504On create, the batch exceeded the 10-second address-resolution budget. Nothing is stored.