Skip to main content

Subscribers API

POST /api/v1/subscribers/upsert​

Creates or updates a subscriber record, keyed by external_id. Authenticated with the publishable SDK key (X-SDK-Key header). Idempotent: re-sending the same body converges on the same record, which is what makes retrying pipelines (Zapier, reverse-ETL) safe.

Request Body​

{
"external_id": "user-123",
"email": "user@example.com",
"attributes": {
"plan": "pro",
"country": "US"
}
}

external_id is the only required field. An optional consent assertion records an express email opt-in alongside the upsert. An optional claim_token is the one-time hober_claim token a subscription form's redirect carries: it takes over the form signup for that address, as the server identify does by email. The browser SDK sends it for you. A token issued for another address than the request's email is ignored, and the identity rules below still apply.

An update merges into the stored subscriber; it never replaces it:

You sendResult
a field you omit (email, attributes, or an attribute key)the stored value is kept
an attribute key with a valuethat key is set; other stored keys are kept
an attribute key set to nullthat key is removed
"email": ""the stored email is cleared

So an app can call identify with only external_id on every launch without erasing attributes set from your backend or an import.

Response​

200 confirming the record. The SDK key is publishable, so this response returns only what the caller already knows: email and attributes echo the values sent in this request (empty when omitted), never the stored profile. Read stored profiles through the dashboard API. id is the Hober subscriber id the SDKs use for device registration.

{
"id": "8a2f6c1e-…",
"external_id": "user-123",
"email": "user@example.com",
"attributes": "{\"plan\":\"pro\",\"country\":\"US\"}",
"created_at": "2026-07-26T12:00:00Z",
"updated_at": "2026-07-26T12:00:00Z"
}

attributes travels as a JSONB-encoded string (schemaless by design). 401 — missing or invalid SDK key. 403 IDENTITY_VERIFICATION_REQUIRED — the change to an existing subscriber needs an X-Hober-Identity token (see identity verification): replacing its email always does, and every write does under enforce. 422 — validation failure naming the field.

POST /v1/subscribers/identify​

Identifies one of your signed-in users from your backend. Authenticated with a server key that carries subscribers:write (Authorization: Bearer hober_srv_…). The body is the upsert body above (external_id required; email, attributes and consent optional), and it merges the same way. Your backend has verified its own user, so no X-Hober-Identity token is needed.

Claiming a form signup. Someone who signs up through a subscription form gets a provisional subscriber with a Hober-assigned id (hf_…). When you identify a user with the same email, that user takes it over:

Your external_idResultclaim
is newthe form subscriber is renamed to your id. Consent, answers, lists, devices and event history stay on itpromoted
already existsthe form subscriber is merged into yours and deleted. Lists are combined, form answers fill only the attributes yours lacks, and the most recent consent record wins per channelmerged
any, and no form subscriber has that emaila plain upsertnone

Only form subscribers are ever claimed: two of your own ids are never merged by email. Ids starting with hf_ are reserved and refused with 422.

Response​

200. The response names the subscriber and what the claim did. A write key is not a read key, so it never returns the stored email or attributes.

{
"id": "8a2f6c1e-…",
"external_id": "user-123",
"claim": "promoted",
"created_at": "2026-10-12T09:30:00Z",
"updated_at": "2026-10-13T12:00:00Z"
}

401 — missing or unknown server key. 403 FORBIDDEN — the key does not carry subscribers:write. 422 — validation failure. 429 SUBSCRIBER_LIMIT_REACHED — creating a new subscriber is over the plan limit.

DELETE /api/v1/subscribers/{id}​

Authenticated with a dashboard bearer token (see Authentication). Permanently deletes a single subscriber and all associated devices and list memberships. Delivery log rows are anonymised (foreign keys set to NULL) rather than deleted.

For GDPR compliance details, cascade behaviour, and the operator runbook, see the GDPR Data Retention Policy guide.

Path parameters​

ParameterTypeDescription
idstring (UUID)Hober subscriber UUID

Response​

204 No Content on success. No response body.

Error responses​

StatusMeaning
401Missing or invalid bearer token
404Subscriber not found

POST /api/v1/subscribers/bulk-delete​

Permanently deletes up to 1,000 subscribers in one GDPR-compliant transaction. Authenticated with a dashboard bearer token. IDs not found in your workspace are returned in not_found and are not treated as errors.

Request body​

{
"subscriber_ids": ["uuid-1", "uuid-2", "uuid-3"]
}
FieldTypeDescription
subscriber_idsstring[]Hober subscriber UUIDs. 1–1,000 per request.

Response​

200 OK:

{
"deleted": 2,
"not_found": ["uuid-3"]
}

Error responses​

StatusMeaning
401Missing or invalid bearer token
422Empty list, or more than 1,000 IDs supplied

For cascade behaviour see the GDPR Data Retention Policy guide.