curl --request POST \
--url https://apix.spotzee.com/api/client/users/batch \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
[
{
"anonymous_id": "anon-2c8a3e",
"external_id": "cust-9f4b21",
"email": "jane@example.com",
"phone": "+61400123456",
"timezone": "Australia/Sydney",
"locale": "en-AU",
"data": {
"first_name": "Jane",
"plan": "pro"
}
}
]
'import requests
url = "https://apix.spotzee.com/api/client/users/batch"
payload = [
{
"anonymous_id": "anon-2c8a3e",
"external_id": "cust-9f4b21",
"email": "jane@example.com",
"phone": "+61400123456",
"timezone": "Australia/Sydney",
"locale": "en-AU",
"data": {
"first_name": "Jane",
"plan": "pro"
}
}
]
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify([
{
anonymous_id: 'anon-2c8a3e',
external_id: 'cust-9f4b21',
email: 'jane@example.com',
phone: '+61400123456',
timezone: 'Australia/Sydney',
locale: 'en-AU',
data: {first_name: 'Jane', plan: 'pro'}
}
])
};
fetch('https://apix.spotzee.com/api/client/users/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://apix.spotzee.com/api/client/users/batch"
payload := strings.NewReader("[\n {\n \"anonymous_id\": \"anon-2c8a3e\",\n \"external_id\": \"cust-9f4b21\",\n \"email\": \"jane@example.com\",\n \"phone\": \"+61400123456\",\n \"timezone\": \"Australia/Sydney\",\n \"locale\": \"en-AU\",\n \"data\": {\n \"first_name\": \"Jane\",\n \"plan\": \"pro\"\n }\n }\n]")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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))
}{
"results": [
{
"index": 0,
"external_id": "cust-9f4b21",
"anonymous_id": "<string>",
"user": {
"id": 1024,
"project_id": 42,
"external_id": "cust-9f4b21",
"created_at": "2026-04-28T05:14:00.000Z",
"updated_at": "2026-04-28T05:14:00.000Z",
"anonymous_id": "anon-2c8a3e",
"email": "jane@example.com",
"phone": "+61400123456",
"timezone": "Australia/Sydney",
"locale": "en-AU",
"data": {
"first_name": "Jane",
"last_name": "Doe",
"plan": "pro"
},
"has_push_device": true,
"devices": [
{}
]
},
"error": {
"code": "resource_missing",
"message": "User identity could not be resolved."
}
}
],
"succeeded": 2,
"failed": 0
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}Bulk upsert users (synchronous)
Creates or updates up to 100 users in a single call and reports per-item success or failure before returning. Each input must include either anonymous_id or external_id; supplying both links the two identifiers. Use this when the calling system needs to react to partial failures inline; use PATCH /users instead for fire-and-forget queued processing.
Idempotent — pass an Idempotency-Key header to make safely retryable. On a replay the original response is returned with Idempotent-Replayed: true. See the API conventions guide for the full state machine, TTL, and mismatch behaviour.
curl --request POST \
--url https://apix.spotzee.com/api/client/users/batch \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
[
{
"anonymous_id": "anon-2c8a3e",
"external_id": "cust-9f4b21",
"email": "jane@example.com",
"phone": "+61400123456",
"timezone": "Australia/Sydney",
"locale": "en-AU",
"data": {
"first_name": "Jane",
"plan": "pro"
}
}
]
'import requests
url = "https://apix.spotzee.com/api/client/users/batch"
payload = [
{
"anonymous_id": "anon-2c8a3e",
"external_id": "cust-9f4b21",
"email": "jane@example.com",
"phone": "+61400123456",
"timezone": "Australia/Sydney",
"locale": "en-AU",
"data": {
"first_name": "Jane",
"plan": "pro"
}
}
]
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify([
{
anonymous_id: 'anon-2c8a3e',
external_id: 'cust-9f4b21',
email: 'jane@example.com',
phone: '+61400123456',
timezone: 'Australia/Sydney',
locale: 'en-AU',
data: {first_name: 'Jane', plan: 'pro'}
}
])
};
fetch('https://apix.spotzee.com/api/client/users/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://apix.spotzee.com/api/client/users/batch"
payload := strings.NewReader("[\n {\n \"anonymous_id\": \"anon-2c8a3e\",\n \"external_id\": \"cust-9f4b21\",\n \"email\": \"jane@example.com\",\n \"phone\": \"+61400123456\",\n \"timezone\": \"Australia/Sydney\",\n \"locale\": \"en-AU\",\n \"data\": {\n \"first_name\": \"Jane\",\n \"plan\": \"pro\"\n }\n }\n]")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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))
}{
"results": [
{
"index": 0,
"external_id": "cust-9f4b21",
"anonymous_id": "<string>",
"user": {
"id": 1024,
"project_id": 42,
"external_id": "cust-9f4b21",
"created_at": "2026-04-28T05:14:00.000Z",
"updated_at": "2026-04-28T05:14:00.000Z",
"anonymous_id": "anon-2c8a3e",
"email": "jane@example.com",
"phone": "+61400123456",
"timezone": "Australia/Sydney",
"locale": "en-AU",
"data": {
"first_name": "Jane",
"last_name": "Doe",
"plan": "pro"
},
"has_push_device": true,
"devices": [
{}
]
},
"error": {
"code": "resource_missing",
"message": "User identity could not be resolved."
}
}
],
"succeeded": 2,
"failed": 0
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}{
"status": "error",
"code": "resource_missing",
"message": "User usr_01HXY7Z9K8M5J2N4P6Q8R0S1T2 was not found in this project.",
"error": "<string>",
"title": "Resource missing",
"type": "https://docs.spotzee.com/main-api/errors#resource_missing",
"request_id": "req_01HXY7Z9K8M5J2N4P6Q8R0S1T2",
"param": "id",
"errors": [
{
"param": "email",
"code": "parameter_invalid_format",
"message": "Must be a valid email address."
}
]
}Authorizations
Project-scoped secret API key (sk_…). Pass in the Authorization: Bearer <key> header. Grants access to the project the key was issued for.
Body
1 - 100 elements- Option 1
- Option 2
A single user upsert. At least one of anonymous_id or external_id must be present. When both are present they are linked.
Anonymous tracking identifier captured before the user was identified.
"anon-2c8a3e"
Optional system-of-record identifier to attach to this anonymous user.
"cust-9f4b21"
User’s email address. Validated against RFC 5322 on write.
"jane@example.com"
User’s phone number. E.164 preferred; other formats are normalised when possible.
"+61400123456"
IANA timezone (for example Australia/Sydney).
50"Australia/Sydney"
BCP-47 locale tag (for example en-AU).
255"en-AU"
Free-form custom attributes attached to the user. Used in segmentation and template rendering.
{ "first_name": "Jane", "plan": "pro" }
Response
Per-item upsert outcomes. Partial success is allowed.
Synchronous result of a bulk user upsert. Partial success is allowed.
Per-item outcomes in the same order as the request body.
Hide child attributes
Hide child attributes
Position of this item in the request body, zero-indexed.
0
External identifier supplied by the caller for this user, when available.
"cust-9f4b21"
Anonymous identifier supplied by the caller for this user, when available.
The persisted user, present when the item upserted successfully.
Hide child attributes
Hide child attributes
Numeric identifier. Use external_id as the stable cross-system reference.
1024
Identifier of the project this user belongs to.
42
Stable identifier supplied by the calling system. Treated as the user’s primary key for upserts.
"cust-9f4b21"
Time the user was first created. ISO 8601.
"2026-04-28T05:14:00.000Z"
Time the user was last modified. ISO 8601.
"2026-04-28T05:14:00.000Z"
Anonymous tracking identifier captured before the user was identified, when available.
"anon-2c8a3e"
User’s email address. Format-validated on write.
"jane@example.com"
User’s phone number in E.164 format on read.
"+61400123456"
IANA timezone used for time-of-day delivery scheduling.
"Australia/Sydney"
BCP-47 locale used for content rendering.
"en-AU"
Free-form custom attributes attached to the user. Used in segmentation and template rendering.
{
"first_name": "Jane",
"last_name": "Doe",
"plan": "pro"
}
True when the user has at least one registered push device.
Registered push devices, when included.
Failure detail, present when the item could not be persisted.
Hide child attributes
Hide child attributes
Per-item error code drawn from the canonical 16-code catalogue.
resource_missing, resource_already_exists, state_conflict, archived_user_conflict, user_capacity_exhausted, parameter_missing, parameter_invalid_empty, parameter_invalid_format, parameter_unknown, validation_failed, authentication_required, permission_denied, idempotency_key_mismatch, idempotency_key_invalid, idempotency_in_progress, rate_limited, version_unsupported, version_required, webhook_signature_invalid, quota_exceeded, service_unavailable, internal_error "resource_missing"
Human-readable, en-AU explanation of why this item failed.
"User identity could not be resolved."
Count of items that upserted successfully.
2
Count of items that failed.
0
Was this page helpful?