> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.zip.tax/v-6-0/guides/merchant-compliance-solutions/nexus-management/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.zip.tax/_mcp/server. # Nexus Management 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](self-managed-cart-calculation) depends on. This applies to [self-managed merchants](self-managed-merchants) only. A [TaxCloud-connected merchant's](taxcloud-connected-merchants) 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: | Kind | How it arises | Recorded how | | --------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | **Physical presence** | An office, store, warehouse, inventory, employee, or other in-state presence | Declared by you, through the endpoints on this page | | **Economic nexus** | Sales into a state cross that state's sales or transaction threshold | Derived from sales activity, not declared. See [economic nexus](#economic-nexus) below | See [Collection Requirements and Nexus](../reference/collection-requirements-and-nexus) for background on the legal concepts, and [Economic Thresholds](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. | Field | Type | Required | Description | | --------------------- | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `locationType` | string | Yes | What kind of presence this is. One of the [seven types](#location-types). | | `address` | string | Yes | The location's US address, as a single line. Max 255 characters. Geocoded on write. | | `registered` | boolean | No | Whether the merchant is registered to collect sales tax in this location's state. Defaults to `false`. | | `isFulfillmentOrigin` | boolean | No | Whether goods actually ship from here. This is the field origin-sourcing consults. [Defaults by `locationType`](#fulfillment-origin). | | `name` | string | No | Your own label, for example `TestCo Texas Distribution Center`. Max 255 characters. Returned as-is and never used in a calculation. | | `referenceId` | string | No | The ID you use for this location in your own system, for example `warehouse-123`. Max 255 characters. | | `locationId` | string | — | Server-issued on create and returned on every read, for example `P-6dc371de-00a4-44bf-8a88-2bcab2f15041`. Use it to update and delete. | ### Location types | `locationType` | Covers | | -------------- | --------------------------------------------------------------------------- | | `office` | Corporate, administrative, or branch offices | | `store` | Retail storefronts | | `warehouse` | Storage facilities holding the merchant's inventory | | `fulfillment` | Third-party fulfillment centers, including marketplace networks such as FBA | | `personnel` | Employees or contractors working in a state | | `property` | Inventory or equipment held in a state | | `temporary` | Short-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`: | `locationType` | Default `isFulfillmentOrigin` | | ---------------------------------------------- | ----------------------------- | | `warehouse`, `fulfillment`, `store` | `true` | | `office`, `personnel`, `property`, `temporary` | `false` | > **Warning** > > 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: | Direction | Value | | --------- | ------------------------------------------------------ | | Sent | `1401 Lavaca St Austin TX 78701` | | Returned | `1401 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 ### Request POST [https://api.zip-tax.com/merchant/nexus/create](https://api.zip-tax.com/merchant/nexus/create) ```curl curl -X POST https://api.zip-tax.com/merchant/nexus/create \ -H "X-API-KEY: " \ -H "Content-Type: application/json" \ -d '{ "locations": [ { "address": "1401 Lavaca St Austin TX 78701", "locationType": "office" } ], "merchantId": "merchantId" }' ``` ```python import requests url = "https://api.zip-tax.com/merchant/nexus/create" payload = { "locations": [ { "address": "1401 Lavaca St Austin TX 78701", "locationType": "office" } ], "merchantId": "merchantId" } headers = { "X-API-KEY": "", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript const url = 'https://api.zip-tax.com/merchant/nexus/create'; const options = { method: 'POST', headers: {'X-API-KEY': '', 'Content-Type': 'application/json'}, body: '{"locations":[{"address":"1401 Lavaca St Austin TX 78701","locationType":"office"}],"merchantId":"merchantId"}' }; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://api.zip-tax.com/merchant/nexus/create" payload := strings.NewReader("{\n \"locations\": [\n {\n \"address\": \"1401 Lavaca St Austin TX 78701\",\n \"locationType\": \"office\"\n }\n ],\n \"merchantId\": \"merchantId\"\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("X-API-KEY", "") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://api.zip-tax.com/merchant/nexus/create") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["X-API-KEY"] = '' request["Content-Type"] = 'application/json' request.body = "{\n \"locations\": [\n {\n \"address\": \"1401 Lavaca St Austin TX 78701\",\n \"locationType\": \"office\"\n }\n ],\n \"merchantId\": \"merchantId\"\n}" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.zip-tax.com/merchant/nexus/create") .header("X-API-KEY", "") .header("Content-Type", "application/json") .body("{\n \"locations\": [\n {\n \"address\": \"1401 Lavaca St Austin TX 78701\",\n \"locationType\": \"office\"\n }\n ],\n \"merchantId\": \"merchantId\"\n}") .asString(); ``` ```php request('POST', 'https://api.zip-tax.com/merchant/nexus/create', [ 'body' => '{ "locations": [ { "address": "1401 Lavaca St Austin TX 78701", "locationType": "office" } ], "merchantId": "merchantId" }', 'headers' => [ 'Content-Type' => 'application/json', 'X-API-KEY' => '', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://api.zip-tax.com/merchant/nexus/create"); var request = new RestRequest(Method.POST); request.AddHeader("X-API-KEY", ""); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"locations\": [\n {\n \"address\": \"1401 Lavaca St Austin TX 78701\",\n \"locationType\": \"office\"\n }\n ],\n \"merchantId\": \"merchantId\"\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = [ "X-API-KEY": "", "Content-Type": "application/json" ] let parameters = [ "locations": [ [ "address": "1401 Lavaca St Austin TX 78701", "locationType": "office" ] ], "merchantId": "merchantId" ] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://api.zip-tax.com/merchant/nexus/create")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ``` `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 ```bash 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: ```json { "merchantId": "dc835fea-b9fb-4f5e-a253-b896455d673f", "locations": [{ "locationId": "P-6dc371de-00a4-44bf-8a88-2bcab2f15041", "locationType": "warehouse", "name": "TestCo Texas Distribution Center", "address": "1401 Lavaca St, Austin, TX 78701-1634, United States", "registered": true, "isFulfillmentOrigin": true, "referenceId": "warehouse-123" }] } ``` 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. > **Warning** > > 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 ### Request POST [https://api.zip-tax.com/merchant/nexus/list](https://api.zip-tax.com/merchant/nexus/list) ```curl curl -X POST https://api.zip-tax.com/merchant/nexus/list \ -H "X-API-KEY: " \ -H "Content-Type: application/json" \ -d '{ "merchantId": "merchantId" }' ``` ```python import requests url = "https://api.zip-tax.com/merchant/nexus/list" payload = { "merchantId": "merchantId" } headers = { "X-API-KEY": "", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript const url = 'https://api.zip-tax.com/merchant/nexus/list'; const options = { method: 'POST', headers: {'X-API-KEY': '', 'Content-Type': 'application/json'}, body: '{"merchantId":"merchantId"}' }; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://api.zip-tax.com/merchant/nexus/list" payload := strings.NewReader("{\n \"merchantId\": \"merchantId\"\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("X-API-KEY", "") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://api.zip-tax.com/merchant/nexus/list") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["X-API-KEY"] = '' request["Content-Type"] = 'application/json' request.body = "{\n \"merchantId\": \"merchantId\"\n}" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.zip-tax.com/merchant/nexus/list") .header("X-API-KEY", "") .header("Content-Type", "application/json") .body("{\n \"merchantId\": \"merchantId\"\n}") .asString(); ``` ```php request('POST', 'https://api.zip-tax.com/merchant/nexus/list', [ 'body' => '{ "merchantId": "merchantId" }', 'headers' => [ 'Content-Type' => 'application/json', 'X-API-KEY' => '', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://api.zip-tax.com/merchant/nexus/list"); var request = new RestRequest(Method.POST); request.AddHeader("X-API-KEY", ""); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"merchantId\": \"merchantId\"\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = [ "X-API-KEY": "", "Content-Type": "application/json" ] let parameters = ["merchantId": "merchantId"] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://api.zip-tax.com/merchant/nexus/list")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ``` 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 ```bash 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" }' ``` ```json { "merchantId": "dc835fea-b9fb-4f5e-a253-b896455d673f", "locations": [{ "locationId": "P-6dc371de-00a4-44bf-8a88-2bcab2f15041", "locationType": "warehouse", "name": "TestCo Texas Distribution Center", "address": "1401 Lavaca St, Austin, TX 78701-1634, United States", "registered": true, "isFulfillmentOrigin": true, "referenceId": "warehouse-123" }] } ``` The optional `nexusType` filter accepts `physical` or `economic`. Omit it to return every kind. ## Update a location ### Request POST [https://api.zip-tax.com/merchant/nexus/update](https://api.zip-tax.com/merchant/nexus/update) ```curl curl -X POST https://api.zip-tax.com/merchant/nexus/update \ -H "X-API-KEY: " \ -H "Content-Type: application/json" \ -d '{ "location": { "address": "1401 Lavaca St Austin TX 78701", "locationType": "office" }, "locationId": "6dc371de-00a4-44bf-8a88-2bcab2f15041", "merchantId": "merchantId" }' ``` ```python import requests url = "https://api.zip-tax.com/merchant/nexus/update" payload = { "location": { "address": "1401 Lavaca St Austin TX 78701", "locationType": "office" }, "locationId": "6dc371de-00a4-44bf-8a88-2bcab2f15041", "merchantId": "merchantId" } headers = { "X-API-KEY": "", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript const url = 'https://api.zip-tax.com/merchant/nexus/update'; const options = { method: 'POST', headers: {'X-API-KEY': '', 'Content-Type': 'application/json'}, body: '{"location":{"address":"1401 Lavaca St Austin TX 78701","locationType":"office"},"locationId":"6dc371de-00a4-44bf-8a88-2bcab2f15041","merchantId":"merchantId"}' }; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://api.zip-tax.com/merchant/nexus/update" payload := strings.NewReader("{\n \"location\": {\n \"address\": \"1401 Lavaca St Austin TX 78701\",\n \"locationType\": \"office\"\n },\n \"locationId\": \"6dc371de-00a4-44bf-8a88-2bcab2f15041\",\n \"merchantId\": \"merchantId\"\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("X-API-KEY", "") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://api.zip-tax.com/merchant/nexus/update") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["X-API-KEY"] = '' request["Content-Type"] = 'application/json' request.body = "{\n \"location\": {\n \"address\": \"1401 Lavaca St Austin TX 78701\",\n \"locationType\": \"office\"\n },\n \"locationId\": \"6dc371de-00a4-44bf-8a88-2bcab2f15041\",\n \"merchantId\": \"merchantId\"\n}" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.zip-tax.com/merchant/nexus/update") .header("X-API-KEY", "") .header("Content-Type", "application/json") .body("{\n \"location\": {\n \"address\": \"1401 Lavaca St Austin TX 78701\",\n \"locationType\": \"office\"\n },\n \"locationId\": \"6dc371de-00a4-44bf-8a88-2bcab2f15041\",\n \"merchantId\": \"merchantId\"\n}") .asString(); ``` ```php request('POST', 'https://api.zip-tax.com/merchant/nexus/update', [ 'body' => '{ "location": { "address": "1401 Lavaca St Austin TX 78701", "locationType": "office" }, "locationId": "6dc371de-00a4-44bf-8a88-2bcab2f15041", "merchantId": "merchantId" }', 'headers' => [ 'Content-Type' => 'application/json', 'X-API-KEY' => '', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://api.zip-tax.com/merchant/nexus/update"); var request = new RestRequest(Method.POST); request.AddHeader("X-API-KEY", ""); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"location\": {\n \"address\": \"1401 Lavaca St Austin TX 78701\",\n \"locationType\": \"office\"\n },\n \"locationId\": \"6dc371de-00a4-44bf-8a88-2bcab2f15041\",\n \"merchantId\": \"merchantId\"\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = [ "X-API-KEY": "", "Content-Type": "application/json" ] let parameters = [ "location": [ "address": "1401 Lavaca St Austin TX 78701", "locationType": "office" ], "locationId": "6dc371de-00a4-44bf-8a88-2bcab2f15041", "merchantId": "merchantId" ] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://api.zip-tax.com/merchant/nexus/update")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ``` Identify the location with `locationId` at the top level, and send its new contents in a `location` object. > **Warning** > > `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 ```bash 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: ```json { "merchantId": "dc835fea-b9fb-4f5e-a253-b896455d673f", "location": { "locationId": "P-6dc371de-00a4-44bf-8a88-2bcab2f15041", "locationType": "warehouse", "name": "TestCo Texas Distribution Center", "address": "1401 Lavaca St, Austin, TX 78701-1634, United States", "registered": true, "isFulfillmentOrigin": true, "referenceId": "warehouse-123" } } ``` 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 ### Request POST [https://api.zip-tax.com/merchant/nexus/delete](https://api.zip-tax.com/merchant/nexus/delete) ```curl curl -X POST https://api.zip-tax.com/merchant/nexus/delete \ -H "X-API-KEY: " \ -H "Content-Type: application/json" \ -d '{ "locationId": "6dc371de-00a4-44bf-8a88-2bcab2f15041", "merchantId": "merchantId" }' ``` ```python import requests url = "https://api.zip-tax.com/merchant/nexus/delete" payload = { "locationId": "6dc371de-00a4-44bf-8a88-2bcab2f15041", "merchantId": "merchantId" } headers = { "X-API-KEY": "", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript const url = 'https://api.zip-tax.com/merchant/nexus/delete'; const options = { method: 'POST', headers: {'X-API-KEY': '', 'Content-Type': 'application/json'}, body: '{"locationId":"6dc371de-00a4-44bf-8a88-2bcab2f15041","merchantId":"merchantId"}' }; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://api.zip-tax.com/merchant/nexus/delete" payload := strings.NewReader("{\n \"locationId\": \"6dc371de-00a4-44bf-8a88-2bcab2f15041\",\n \"merchantId\": \"merchantId\"\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("X-API-KEY", "") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://api.zip-tax.com/merchant/nexus/delete") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["X-API-KEY"] = '' request["Content-Type"] = 'application/json' request.body = "{\n \"locationId\": \"6dc371de-00a4-44bf-8a88-2bcab2f15041\",\n \"merchantId\": \"merchantId\"\n}" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.zip-tax.com/merchant/nexus/delete") .header("X-API-KEY", "") .header("Content-Type", "application/json") .body("{\n \"locationId\": \"6dc371de-00a4-44bf-8a88-2bcab2f15041\",\n \"merchantId\": \"merchantId\"\n}") .asString(); ``` ```php request('POST', 'https://api.zip-tax.com/merchant/nexus/delete', [ 'body' => '{ "locationId": "6dc371de-00a4-44bf-8a88-2bcab2f15041", "merchantId": "merchantId" }', 'headers' => [ 'Content-Type' => 'application/json', 'X-API-KEY' => '', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://api.zip-tax.com/merchant/nexus/delete"); var request = new RestRequest(Method.POST); request.AddHeader("X-API-KEY", ""); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"locationId\": \"6dc371de-00a4-44bf-8a88-2bcab2f15041\",\n \"merchantId\": \"merchantId\"\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = [ "X-API-KEY": "", "Content-Type": "application/json" ] let parameters = [ "locationId": "6dc371de-00a4-44bf-8a88-2bcab2f15041", "merchantId": "merchantId" ] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://api.zip-tax.com/merchant/nexus/delete")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ``` #### cURL ```bash 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" }' ``` ```json { "merchantId": "dc835fea-b9fb-4f5e-a253-b896455d673f", "locationId": "P-6dc371de-00a4-44bf-8a88-2bcab2f15041", "message": "location removed" } ``` 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](economic-thresholds) for how the thresholds are constructed and where to find the data. ## Errors | Status | Meaning | | ------ | -------------------------------------------------------------------------------------------- | | `400` | Malformed request body. | | `401` | Missing or invalid API key. | | `403` | The merchant is TaxCloud-connected. These endpoints are for self-managed merchants only. | | `404` | The `locationId` does not exist, or has already been deleted. | | `422` | An address could not be resolved to a US state. On `create`, nothing in the batch is stored. | | `429` | Rate limit exceeded. See [Rate Limiting & Errors](../reference/rate-limiting-errors). | | `504` | On `create`, the batch exceeded the 10-second address-resolution budget. Nothing is stored. | ## Related #### [Self-Managed Merchants](self-managed-merchants) The compliance model where your platform tracks nexus and the merchant handles their own filing. #### [Self-Managed Cart Calculation](self-managed-cart-calculation) The calculation that consults the nexus footprint you record here. #### [Economic Thresholds](economic-thresholds) How state sales and transaction thresholds work, with per-state reference data. #### [Collection Requirements and Nexus](../reference/collection-requirements-and-nexus) Background on nexus and when a seller must collect sales tax. > Record the physical locations a self-managed merchant operates from, so Ziptax knows where they collect and how their sales are sourced.