Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.spotzee.com/llms.txt

Use this file to discover all available pages before exploring further.

Use this flow when you already have a customer record system (a CRM, a billing platform, your own database) and want Spotzee to mirror those users so you can market to them.

What you’ll build

A repeatable job that:
  1. Reads a batch of users from your source system.
  2. Sends them to Spotzee with external_id set to your stable customer ID.
  3. Uses an Idempotency-Key so timeouts and retries are safe.
  4. Walks through every page of source data without re-importing what’s already in.

Prerequisites

You’ll need a sk_ project key with write access. See Authentication for how to mint one.

Walkthrough

1

Pick a stable identifier

Choose the field in your source system that uniquely identifies a customer and never changes. Usually the primary key from your customers table. Pass it to Spotzee as external_id on every user.Spotzee uses external_id as the upsert key: re-syncing the same external id updates the existing user rather than creating a duplicate.
2

Map your fields to Spotzee's schema

Spotzee users have a small set of first-class fields (external_id, email, phone, timezone, locale) and a flexible data object for anything else, including first_name, last_name, and any custom attributes. Map your CRM columns to first-class fields where they line up; put everything else into data.
Your columnSpotzee field
customers.idexternal_id
customers.email_addressemail
customers.phone_e164phone
customers.localelocale
customers.first_name, last_namedata.first_name, data.last_name
everything elsedata.<your_key>
3

Pick the batch endpoint that fits

Two batch endpoints are available. Both accept up to 100 users per call as a bare JSON array:
EndpointBehaviourUse when
POST /users/batchSynchronous: the response reports per-item success or failure before returningYou want immediate confirmation of which items failed
PATCH /usersAsynchronous: queued for processing, returns 204 No ContentFire-and-forget bulk imports where eventual consistency is fine
100 per call is the sweet spot for throughput; smaller batches limit the blast radius of a partial failure when using the synchronous form.
4

Send each batch with an idempotency key

Generate a unique key per batch. A deterministic key derived from the first and last external_id works well, since a retry from a queue then uses the same key.
POST /users/batch HTTP/1.1
Host: apix.spotzee.com
Authorization: Bearer sk_…
Idempotency-Key: sync-batch-cust_001-cust_100
Spotzee-Version: 2026-04-28
Content-Type: application/json

[
  {
    "external_id": "cust_001",
    "email": "ada@example.com",
    "data": {
      "first_name": "Ada",
      "last_name": "Lovelace",
      "lifetime_value": 4250
    }
  }
]
The body is a bare JSON array, not wrapped in an object. Each item must include either external_id or anonymous_id (or both, to link them).
5

Handle partial failures

The synchronous endpoint (POST /users/batch) returns a per-item result array. Items that succeeded are committed; failed items are returned with their identifier and a code from the error catalogue. Retry only the failed items in a fresh request.The async endpoint (PATCH /users) returns 204 immediately and does not surface per-item errors. Use the synchronous form when you need that visibility.
6

Walk every page of source data

Use cursor pagination on your source system the same way you’d page Spotzee. See Pagination. Persist the cursor so a crashed job resumes where it stopped.

Pitfalls to avoid

Don’t use the user’s email address as external_id. Emails change. A stable, immutable customer ID (like the primary key of your customers table) is the right shape.
  • Don’t loop one user at a time. The user upsert endpoints are batch-only (POST /users/batch synchronous, PATCH /users async). Both accept up to 100 per call. Pack your batches.
  • Don’t reuse the same idempotency key for two different batches. Spotzee returns 409 idempotency_key_mismatch if you do. See Idempotency for the exact semantics.
  • Don’t write back to your source from the response. Spotzee returns its own id for each user, but you should key off external_id on your side. That way a re-import doesn’t break.

Reference