Accreditation
An accreditation application is a request to be admitted in a category — Press, Contractor, VIP — reviewed by the organiser and, if approved, issued a credential. This endpoint reads the outcome for one registration.
It has its own key permission:
registration.accreditation.read.registration.readdoes not confer it. A key you already hold for attendee lists gained nothing when this shipped, and never will — a new capability gets a new permission, so widening what a key can see is always an act by the workspace that owns it.
Read a decision
GET /api/public/v1/registrations/{id}/accreditation{
"data": {
"id": "acc_2f9…",
"decision": "APPROVED",
"status": "APPROVED",
"category": { "code": "PRESS", "name": "Press", "nameAr": "صحافة" },
"submittedAt": "2026-09-01T10:00:00.000Z",
"decidedAt": "2026-09-02T11:00:00.000Z",
"credential": {
"issued": true,
"issuedAt": "2026-09-02T11:00:05.000Z",
"revokedAt": null,
"active": true
},
"createdAt": "2026-09-01T09:00:00.000Z",
"updatedAt": "2026-09-02T11:00:05.000Z"
}
}Read decision, not status
decision is the outcome, and its meaning never changes. It is one of
APPROVED, DECLINED, WITHDRAWN, REVOKED, or null while the application
is still being decided.
status is the raw internal row state — DRAFT, SUBMITTED,
UNDER_REVIEW, APPROVED, REJECTED, WITHDRAWN — and it carries one trap we
would rather state than let you discover: a revocation overwrites it to
WITHDRAWN. So on status alone, a credential the organiser revoked is
indistinguishable from an application the applicant withdrew, and an approval
that is later revoked stops looking like an approval. decision separates them:
| what happened | decision | status | credential.issued | credential.active |
|---|---|---|---|---|
| Approved, credential live | APPROVED | APPROVED | true | true |
| Approved, then revoked | REVOKED | WITHDRAWN | true | false |
| Withdrawn by the applicant | WITHDRAWN | WITHDRAWN | false | false |
| Declined by the organiser | DECLINED | REJECTED | false | false |
| Still under review | null | UNDER_REVIEW | false | false |
status is published because it carries lifecycle stages decision cannot
express (is it submitted? under review?). It is not the field to key a decision
off.
A revoked credential
{
"data": {
"id": "acc_2f9…",
"decision": "REVOKED",
"status": "WITHDRAWN",
"category": { "code": "PRESS", "name": "Press", "nameAr": "صحافة" },
"submittedAt": "2026-09-01T10:00:00.000Z",
"decidedAt": "2026-09-02T11:00:00.000Z",
"credential": {
"issued": true,
"issuedAt": "2026-09-02T11:00:05.000Z",
"revokedAt": "2026-09-03T08:00:00.000Z",
"active": false
},
"createdAt": "2026-09-01T09:00:00.000Z",
"updatedAt": "2026-09-03T08:00:00.000Z"
}
}credential.active is the field a door should read. It is
issued && !revoked, computed here rather than left to you, so two integrations
cannot disagree about whether a revoked credential still counts. issued stays
true after a revocation, because “was issued and withdrawn” and “was never
issued” are different facts and both matter.
The credential code is never returned
The credential itself — the value a scanner reads — is not in this response and is not in any read. It is a capability: whoever holds it can present as the accredited person, and there is no second factor behind it. It is shown once, to the organiser, at the moment of approval.
If you are building a door, you do not need it: ask this endpoint whether a credential is active for the registration in front of you.
The reviewer’s decision note is also withheld. It is internal text written about a named person during review, for the organiser’s own record.
Errors
This endpoint returns the standard error codes and adds nothing of its own. Two of them are worth reading in this context:
403 FORBIDDEN means the key is valid but lacks
registration.accreditation.read. A key that reads registrations perfectly well
still gets a 403 here — see the note at the top of this page.
404 NOT_FOUND deliberately covers three cases: no such registration, a
registration with no accreditation application, and a registration belonging to
another workspace. Distinguishing them would let an id be probed for existence,
so they answer identically.
If a registration has more than one application
Nothing stops a registration carrying several applications — a re-application
after a decline, for instance. This endpoint answers with the one that holds a
credential, falling back to the most recently created when none does. That is
deliberate: credential.active is the field a door reads, and answering with a
newer application while an older one holds a live credential would refuse
somebody who should be let in.
Not here yet
There is no list endpoint — this reads one registration’s decision. A directory of applications is a separate, wider surface and will arrive as its own change rather than by widening this one.
There are no writes. Applications are created in the app or at the door; an API that submitted one would invite bulk submission of other people’s identity documents.