Skip to main content

ID prefixes

Every object has an opaque, prefixed identifier. The prefix tells you what type of object it is; the rest of the ID has no meaning and shouldn't be parsed.

card_01HX8ZQ2K4M7P9RSTV
└──┘ └────────────────┘
type opaque

The full list​

PrefixObject
prog_Program
chd_Cardholder
acct_Account
card_Card
auth_Authorization
txn_Transaction
disp_Dispute
tok_Network token
epkg_eSIM data package
esim_eSIM
eord_eSIM order
etop_eSIM top-up
whk_Webhook endpoint
evt_Event
req_Request (used in Aleta-Request-Id and the error request_id)
oc_OAuth client
oat_Access token record (shown in Cockpit, never sent over the wire)

Access tokens are different. They aren't object IDs and don't follow this format. They're opaque secrets prefixed with at_test_ for sandbox or at_live_ for production.

Using a token in the wrong environment will fail rather than accidentally accessing objects from the other environment.

Format​

The part after the prefix is a 26-character uppercase Crockford base-32 string.

Full IDs match:

^[a-z]+_[0-9A-HJKMNP-TV-Z]{26}$

Crockford base-32 leaves out I, L, O, and U because they're easy to confuse with other characters when copying IDs from things like support tickets.

When storing IDs, size your database column for up to 64 characters. IDs are currently shorter than that, but the format and maximum length aren't something your integration should rely on.

Rules​

  1. Don't parse IDs. The opaque part has no meaning. It's not a timestamp, sequence number, hash, or anything else you can reproduce.
  2. Don't sort by ID. If you need chronological order, sort by created_at.
  3. Don't assume IDs are portable between environments. The same string in sandbox and production refers to unrelated objects.
  4. Use the prefix for basic validation. For example, if your code expects a card_ ID but receives an acct_ ID, reject it before making a request.
  5. Store IDs as strings. Keep the prefix and don't convert them to numbers.

Why IDs are opaque​

There are a couple of practical reasons.

First, sequential IDs can leak information about your volume. If someone signs up and creates one card, they could potentially infer roughly how many cards you've issued. Sequential IDs also make enumeration easier.

More importantly, opaque IDs give us room to change what's happening behind the scenes. The ID you store belongs to Aleta, rather than exposing a key from some downstream system. If our internal processing changes, the IDs you've already stored can keep working.

That's intentional. Exposing an upstream identifier through the API would make that kind of change much harder.

Your own identifiers​

Most resources accept a reference field for your own identifier. It's returned when you read the resource and included in webhook payloads:

{
"id": "card_01HX8ZQ2K4M7P9RSTV",
"reference": "employee-4471-card-2"
}

reference is indexed and can be used as a filter:

curl "https://api.aletaplanet.com/v1/cards?reference=employee-4471-card-2"

reference doesn't have to be unique and isn't used for idempotency. If you need idempotency, use Idempotency-Key.