Core Concepts
Resource IDs
Every resource exposed through the Public API has a stable, prefixed
identifier of the form <prefix>_<26 base32 chars>.
msg_01HXYZABCDEFGHJKMNPQRSTVWXPrefix table
Section titled “Prefix table”| Prefix | Resource |
|---|---|
msg_ | Message |
cnv_ | Conversation |
ctc_ | Contact |
lbl_ | Label |
tmpl_ | Template |
wbs_ | Webhook subscription |
wbd_ | Webhook delivery |
evt_ | Event (KCKit envelope payload id) |
key_ | API key |
sec_ | Webhook signing secret |
req_ | Request id (response envelope + X-Request-Id header) |
org_ | Organisation |
usr_ | User (conversation assignee) |
Format
Section titled “Format”- Length: 4 (prefix) + 1 (
_) + 26 (id body) = 31 characters total for most resources.tmpl_*is 32 chars (5-char prefix). - Alphabet: Crockford base32 (
0-9andA-ZminusI L O U). Always uppercase. - URL-safe: No characters require percent-encoding.
Stability commitments
Section titled “Stability commitments”- Permanent. Once Kirim hands you an id, that id refers to that exact resource for as long as the resource exists. Hard deletes remove the row entirely, but the id is never reused for a new row.
- Opaque. The body of the id encodes no public meaning. Do not
parse, decode, or sort by it. Order resources by
created_at(always returned alongside). - Globally unique within Kirim. No two resources share an id, even across organisations.
- Tenant-scoped retrieval. Every endpoint that takes an id
enforces that the resource belongs to the caller’s organisation. A
cross-org id returns
404 resource_not_found— never403, to avoid leaking existence.
What about internal IDs?
Section titled “What about internal IDs?”Internally Kirim uses 12-character nanoids as primary keys. The
public id (msg_…) is stored on a separate column (external_id)
and is the only id form ever returned through the API. If you see a
shorter id-shaped string somewhere in a payload (e.g. assigned_to
on conversations), it’s the internal user id — the only resource
without an external_id contract in v1. A future migration may
extend the usr_ prefix to users.
Anti-patterns
Section titled “Anti-patterns”- Don’t sort by id. Crockford base32 is lexicographic but the id
body is not strictly time-monotonic across all resources. Sort by
created_atinstead. - Don’t substring-match prefixes for routing. Use the resource type implied by the endpoint, not the id prefix on the wire.
- Don’t store IDs you didn’t get from Kirim. Generated ids (yours
or anyone else’s) won’t match the storage format and will fail
validation with
400 invalid_field_value.