Skip to main content
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.
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: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.
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