Carillon docs

Devices

Registration, user identifiers, permissions, tags, and token invalidation.

A device is an APNs or FCM token registered to one Carillon app. Use its id to target it in audience.device_ids.

Registration

The SDK calls POST /v1/devices with a mobile key. Registering the same token in the same app updates the existing device and returns the same ID. A new token creates a new device.

If you already have a provider token, you can register it with the API or import tokens from CSV.

User identifiers

Set external_id with identify() and clear it on sign-out with clearIdentity() (or identify(null) in React Native).

  • Two devices can have the same external_id.
  • Changing the signed-in user updates the identifier on the existing device.
  • A reinstall that obtains a new token creates a new device. The old token remains until the provider invalidates it.

external_id is optional. It does not replace the device ID used in a send request.

What registration collects

FieldWhere it comes from
tokenThe APNs or FCM token, exactly as the device received it
platformios or android
environmentDetected by the SDK from the build it is running in, never configured
external_ididentify(), and null erases it
tagssetTags(), merged per key; null removes a key
timezone_idThe IANA identifier the OS reports, never an offset
localeBCP 47
app_version, app_buildThe marketing version, and the monotonic build behind it
bundle_idThe binary's own identity, and what an APNs topic is checked against
os_versionVerbatim, never normalised
push_permissionallowed, denied, provisional or undetermined
sdk_versionThe Carillon SDK's own version
opted_inYour app's own opt-out switch, through optIn() and optOut()

The SDK does not collect advertising identifiers, carrier, IP geolocation, screen metrics, battery state, or device model.

Registration and permission are separate

configure() starts token acquisition and registration without showing a permission prompt. Call requestPermission() separately when your app should ask to display notifications. Registration can succeed before permission is granted.

push_permission records the operating system permission. opted_in records your app's preference, set with optIn() or optOut(). Opting in does not grant operating system permission.

Provider environment

Platform or buildEnvironment
iOS development-signed build or supported simulatorsandbox
iOS TestFlight or App Store buildproduction
AndroidFCM; the API retains production for compatibility

FCM has no sandbox/production endpoint distinction, so the dashboard labels Android devices FCM. The API's environment: production is a compatibility value, not an assertion that an Android installation is a production customer. It does not select Carillon live/test mode or separate your development users.

The SDK detects the APNs environment. APNs sandbox and production tokens are not interchangeable. If registration fails, inspect debugInfo() and the platform registration error.

Token lifecycle

When APNs reports 410 Unregistered or FCM reports UNREGISTERED, Carillon invalidates the token and stops sending to it. The device remains visible in the dashboard. Disabling notification display is separate from token invalidation.

An invalidated device carries invalidated_at and invalidation_reason. The reason is Superseded when the row lost its token to a newer registration of the same installation, and otherwise the provider's own word, such as Unregistered or UNREGISTERED. Both are null on a device that can still be sent to.

For APNs, the feedback timestamp must be later than the device's registration or re-registration. Older feedback does not invalidate a newly registered token.

Tags and opting out

setTags() merges supplied keys with the stored tags. Values can be strings, numbers, or booleans. Omitted keys remain unchanged; null (nil in Swift) removes a key. setTag(name, value) updates one key and removeTag(name) deletes one. An empty map is a no-op. Audience filters can match these values.

Starting with SDK 0.3.0, only pending tag changes are sent. They survive offline use and restart, and are cleared after a successful registration. Later metadata updates do not replay previously acknowledged tags. Earlier SDKs send their full local tag map and can overwrite a server change to the same key.

Your backend can update tags without a push token using a secret key with devices:write:

curl -X PATCH 'https://api.carillon.dev/v1/devices/DEVICE_ID' \
  -H 'Authorization: Bearer YOUR_SECRET_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"tags":{"plan":"pro","trial":null}}'

A successful response is 200 with the updated device. Read it with GET /v1/devices/DEVICE_ID to verify the merged tags. The key selects the app and test/live mode. A mobile key cannot use this endpoint; SDKs update their installation through POST /v1/devices. The patch does not refresh device activity or change registration metadata.

Concurrent updates to different keys are preserved. For the same key, the last applied write wins. The resulting map must fit 50 keys and 4,096 bytes; an oversized merge is rejected without changing the device. On registration, an omitted tags field leaves all tags unchanged; tags: null explicitly clears all tags.

optOut() excludes the device from sending. Call optIn() to reverse the app-level opt-out. Operating system notification permission is controlled separately by the user.

Deleting a device

Deletion needs a secret key with the devices:delete scope; a mobile key cannot delete.

CallResult
DELETE /v1/devices/{id}204. Idempotent: deleting an unknown or already deleted ID also returns 204
DELETE /v1/devices?external_id=user-42200 with { "deleted": n }, every device of that user in the app

Only the device row is deleted. Its deliveries stay in campaign traces with their platform, and the presence rows that already counted the device toward this month's usage are kept, so usage already consumed remains billed. A token the SDK registers again after deletion creates a new device with a new ID.

Deleting is not opting out: to stop sending to an installation that still exists, use optOut() or leave the token to be invalidated by the provider. Delete when the user is erased from your own records, or to remove tokens imported by mistake.

SDK overview · Audience filters · Register a device

Stable installation identity

Updated SDKs send the last confirmed device_id and a persisted random installation_secret on registration. A matching proof lets the API replace the push token on the same row, preserving attributes omitted from the request. The server stores only a SHA-256 hash of the secret and never returns it.

An unknown or foreign ID, a missing/incorrect proof, or a different platform or mode does not authorize reuse of the old row. If the replacement token already belongs to a device in the same app/platform/mode, that row wins and the previous row is invalidated. Subsequent registrations use the returned ID. A conflict with another mode or platform returns 422 device_identity_conflict.

The SDK secret belongs to the installation. Reinstallation can create a new ID. device_id alone is public context, not authentication. Integrations using older SDKs continue to register by token.

On this page