Customers
Upsert customers
Create or update up to 1000 customers in one request. Each customer is matched on its source, source account ID, and source ID, so you can safely send the same request again. Each customer succeeds or fails on its own.
POST
/
customers
/
batch
Upsert Customers
curl --request POST \
--url https://api.taxwire.com/customers/batch \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"data": [
{
"source_id": "CUS-1042",
"name": "Acme Wholesale Inc.",
"source_updated_at": "2026-09-15T08:30:00Z"
},
{
"source_id": "CUS-1043",
"name": "Beta Corp",
"email": "billing@beta.example",
"source_updated_at": "2026-09-15T08:29:41Z"
},
{
"name": "Gamma Supply"
}
]
}
'import requests
url = "https://api.taxwire.com/customers/batch"
payload = { "data": [{
"source_id": "CUS-1042",
"name": "Acme Wholesale Inc.",
"source_updated_at": "2026-09-15T08:30:00Z"
}, {
"source_id": "CUS-1043",
"name": "Beta Corp",
"email": "billing@beta.example",
"source_updated_at": "2026-09-15T08:29:41Z"
}, { "name": "Gamma Supply" }] }
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
data: [
{
source_id: 'CUS-1042',
name: 'Acme Wholesale Inc.',
source_updated_at: '2026-09-15T08:30:00Z'
},
{
source_id: 'CUS-1043',
name: 'Beta Corp',
email: 'billing@beta.example',
source_updated_at: '2026-09-15T08:29:41Z'
},
{name: 'Gamma Supply'}
]
})
};
fetch('https://api.taxwire.com/customers/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.taxwire.com/customers/batch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'data' => [
[
'source_id' => 'CUS-1042',
'name' => 'Acme Wholesale Inc.',
'source_updated_at' => '2026-09-15T08:30:00Z'
],
[
'source_id' => 'CUS-1043',
'name' => 'Beta Corp',
'email' => 'billing@beta.example',
'source_updated_at' => '2026-09-15T08:29:41Z'
],
[
'name' => 'Gamma Supply'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.taxwire.com/customers/batch"
payload := strings.NewReader("{\n \"data\": [\n {\n \"source_id\": \"CUS-1042\",\n \"name\": \"Acme Wholesale Inc.\",\n \"source_updated_at\": \"2026-09-15T08:30:00Z\"\n },\n {\n \"source_id\": \"CUS-1043\",\n \"name\": \"Beta Corp\",\n \"email\": \"billing@beta.example\",\n \"source_updated_at\": \"2026-09-15T08:29:41Z\"\n },\n {\n \"name\": \"Gamma Supply\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<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(string(body))
}HttpResponse<String> response = Unirest.post("https://api.taxwire.com/customers/batch")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"data\": [\n {\n \"source_id\": \"CUS-1042\",\n \"name\": \"Acme Wholesale Inc.\",\n \"source_updated_at\": \"2026-09-15T08:30:00Z\"\n },\n {\n \"source_id\": \"CUS-1043\",\n \"name\": \"Beta Corp\",\n \"email\": \"billing@beta.example\",\n \"source_updated_at\": \"2026-09-15T08:29:41Z\"\n },\n {\n \"name\": \"Gamma Supply\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.taxwire.com/customers/batch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"data\": [\n {\n \"source_id\": \"CUS-1042\",\n \"name\": \"Acme Wholesale Inc.\",\n \"source_updated_at\": \"2026-09-15T08:30:00Z\"\n },\n {\n \"source_id\": \"CUS-1043\",\n \"name\": \"Beta Corp\",\n \"email\": \"billing@beta.example\",\n \"source_updated_at\": \"2026-09-15T08:29:41Z\"\n },\n {\n \"name\": \"Gamma Supply\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"object": "batch",
"summary": {
"created": 1,
"updated": 1,
"stale": 0,
"deleted": 0,
"failed": 1
},
"data": [
{
"index": 0,
"status": "updated",
"customer": {
"id": "cust_01J9Z8Q4E7K2M3N4P5R6S7T8U9",
"source_id": "CUS-1042",
"source": "taxwire",
"source_account_id": "__default__",
"name": "Acme Wholesale Inc.",
"email": "ap@acme.example",
"source_updated_at": "2026-09-15T08:30:00Z",
"created_at": "2026-09-14T20:00:00Z",
"updated_at": "2026-09-15T08:30:05Z"
}
},
{
"index": 1,
"status": "created",
"customer": {
"id": "cust_01J9ZB7V3M8N2K4P6Q1R5S7T9W",
"source_id": "CUS-1043",
"source": "taxwire",
"source_account_id": "__default__",
"name": "Beta Corp",
"email": "billing@beta.example",
"source_updated_at": "2026-09-15T08:29:41Z",
"created_at": "2026-09-15T08:30:05Z",
"updated_at": "2026-09-15T08:30:05Z"
}
},
{
"index": 2,
"status": "failed",
"errors": [
{
"status": "422",
"code": "validation_required_field",
"title": "Missing source_id",
"detail": "Please provide a value for the required source_id field",
"source": {
"pointer": "/data/attributes/data/2/source_id"
}
}
]
}
]
}{
"errors": [
{
"status": "413",
"code": "request_too_large",
"title": "Request Too Large",
"detail": "The request body is 5242881 bytes; this API accepts at most 5242880. Split it into smaller requests."
}
]
}{
"errors": [
{
"status": "422",
"code": "validation_error",
"title": "Validation Error",
"detail": "List should have at most 1000 items after validation, not 1001",
"source": {
"pointer": "/data/attributes/data"
}
}
]
}{
"errors": [
{
"status": "429",
"code": "rate_limit_error",
"title": "Too Many Requests",
"detail": "Rate limit exceeded"
}
]
}{
"errors": [
{
"status": "500",
"code": "system_internal_error",
"title": "Internal Error",
"detail": "An unexpected error occurred. Our team has been notified."
}
]
}Authorizations
APIKeyHeaderHTTPBearer
Body
application/json
Upsert customers request model.
List of customers to create or update, up to 1000 customers and 5 MB per request. Each customer takes the same fields as Create customer. For an existing customer, omitted fields and null values keep the current value. If the same customer appears more than once, every copy fails.
Maximum array length:
1000Show child attributes
Show child attributes
⌘I
Upsert Customers
curl --request POST \
--url https://api.taxwire.com/customers/batch \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"data": [
{
"source_id": "CUS-1042",
"name": "Acme Wholesale Inc.",
"source_updated_at": "2026-09-15T08:30:00Z"
},
{
"source_id": "CUS-1043",
"name": "Beta Corp",
"email": "billing@beta.example",
"source_updated_at": "2026-09-15T08:29:41Z"
},
{
"name": "Gamma Supply"
}
]
}
'import requests
url = "https://api.taxwire.com/customers/batch"
payload = { "data": [{
"source_id": "CUS-1042",
"name": "Acme Wholesale Inc.",
"source_updated_at": "2026-09-15T08:30:00Z"
}, {
"source_id": "CUS-1043",
"name": "Beta Corp",
"email": "billing@beta.example",
"source_updated_at": "2026-09-15T08:29:41Z"
}, { "name": "Gamma Supply" }] }
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
data: [
{
source_id: 'CUS-1042',
name: 'Acme Wholesale Inc.',
source_updated_at: '2026-09-15T08:30:00Z'
},
{
source_id: 'CUS-1043',
name: 'Beta Corp',
email: 'billing@beta.example',
source_updated_at: '2026-09-15T08:29:41Z'
},
{name: 'Gamma Supply'}
]
})
};
fetch('https://api.taxwire.com/customers/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.taxwire.com/customers/batch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'data' => [
[
'source_id' => 'CUS-1042',
'name' => 'Acme Wholesale Inc.',
'source_updated_at' => '2026-09-15T08:30:00Z'
],
[
'source_id' => 'CUS-1043',
'name' => 'Beta Corp',
'email' => 'billing@beta.example',
'source_updated_at' => '2026-09-15T08:29:41Z'
],
[
'name' => 'Gamma Supply'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.taxwire.com/customers/batch"
payload := strings.NewReader("{\n \"data\": [\n {\n \"source_id\": \"CUS-1042\",\n \"name\": \"Acme Wholesale Inc.\",\n \"source_updated_at\": \"2026-09-15T08:30:00Z\"\n },\n {\n \"source_id\": \"CUS-1043\",\n \"name\": \"Beta Corp\",\n \"email\": \"billing@beta.example\",\n \"source_updated_at\": \"2026-09-15T08:29:41Z\"\n },\n {\n \"name\": \"Gamma Supply\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<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(string(body))
}HttpResponse<String> response = Unirest.post("https://api.taxwire.com/customers/batch")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"data\": [\n {\n \"source_id\": \"CUS-1042\",\n \"name\": \"Acme Wholesale Inc.\",\n \"source_updated_at\": \"2026-09-15T08:30:00Z\"\n },\n {\n \"source_id\": \"CUS-1043\",\n \"name\": \"Beta Corp\",\n \"email\": \"billing@beta.example\",\n \"source_updated_at\": \"2026-09-15T08:29:41Z\"\n },\n {\n \"name\": \"Gamma Supply\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.taxwire.com/customers/batch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"data\": [\n {\n \"source_id\": \"CUS-1042\",\n \"name\": \"Acme Wholesale Inc.\",\n \"source_updated_at\": \"2026-09-15T08:30:00Z\"\n },\n {\n \"source_id\": \"CUS-1043\",\n \"name\": \"Beta Corp\",\n \"email\": \"billing@beta.example\",\n \"source_updated_at\": \"2026-09-15T08:29:41Z\"\n },\n {\n \"name\": \"Gamma Supply\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"object": "batch",
"summary": {
"created": 1,
"updated": 1,
"stale": 0,
"deleted": 0,
"failed": 1
},
"data": [
{
"index": 0,
"status": "updated",
"customer": {
"id": "cust_01J9Z8Q4E7K2M3N4P5R6S7T8U9",
"source_id": "CUS-1042",
"source": "taxwire",
"source_account_id": "__default__",
"name": "Acme Wholesale Inc.",
"email": "ap@acme.example",
"source_updated_at": "2026-09-15T08:30:00Z",
"created_at": "2026-09-14T20:00:00Z",
"updated_at": "2026-09-15T08:30:05Z"
}
},
{
"index": 1,
"status": "created",
"customer": {
"id": "cust_01J9ZB7V3M8N2K4P6Q1R5S7T9W",
"source_id": "CUS-1043",
"source": "taxwire",
"source_account_id": "__default__",
"name": "Beta Corp",
"email": "billing@beta.example",
"source_updated_at": "2026-09-15T08:29:41Z",
"created_at": "2026-09-15T08:30:05Z",
"updated_at": "2026-09-15T08:30:05Z"
}
},
{
"index": 2,
"status": "failed",
"errors": [
{
"status": "422",
"code": "validation_required_field",
"title": "Missing source_id",
"detail": "Please provide a value for the required source_id field",
"source": {
"pointer": "/data/attributes/data/2/source_id"
}
}
]
}
]
}{
"errors": [
{
"status": "413",
"code": "request_too_large",
"title": "Request Too Large",
"detail": "The request body is 5242881 bytes; this API accepts at most 5242880. Split it into smaller requests."
}
]
}{
"errors": [
{
"status": "422",
"code": "validation_error",
"title": "Validation Error",
"detail": "List should have at most 1000 items after validation, not 1001",
"source": {
"pointer": "/data/attributes/data"
}
}
]
}{
"errors": [
{
"status": "429",
"code": "rate_limit_error",
"title": "Too Many Requests",
"detail": "Rate limit exceeded"
}
]
}{
"errors": [
{
"status": "500",
"code": "system_internal_error",
"title": "Internal Error",
"detail": "An unexpected error occurred. Our team has been notified."
}
]
}