Skip to main content

5. Cards

Card management operations are available to Station-role terminals only. All endpoints in this section require a token with "role": "station" and an active session grant with the relevant allowedOps entry.


POST /api/cards

Register a new card with the backend. Called by the Station app after writing the initialisation payload to a blank card.

Request headers: Authorization: Bearer <station-token>

Request body:

{
"cardId": "<6-byte hex>",
"userId": 1042,
"name": "Siti Rahayu",
"createdAt": 1746600000,
"keyVersion": 3
}
FieldTypeDescription
cardIdhex string6-byte unique card identifier written to the identity block
userIduint32Backend user account ID to associate with this card
namestringCardholder display name (max 32 bytes UTF-8)
createdAtuint32UTC seconds of issuance timestamp written to the card
keyVersionuint8Key version used during card initialisation

Response (201 Created):

{
"cardId": "<6-byte hex>",
"userId": 1042,
"status": "ACTIVE",
"balance": 0,
"createdAt": 1746600000
}

Error responses:

CodeErrorCause
403 Forbiddeninsufficient_roleCaller is not a station
409 Conflictcard_already_registeredcardId already exists in the backend
422 Unprocessable Entityinvalid_useruserId does not correspond to an active account

GET /api/cards/:cardId

Fetch the backend record for a card. Used by Scout (read-only balance/status view) and Station (pre-operation check).

Request headers: Authorization: Bearer <token> (any role)

Response (200 OK):

{
"cardId": "<6-byte hex>",
"userId": 1042,
"status": "ACTIVE",
"balance": 350000,
"counter": 17,
"createdAt": 1746600000,
"lastActivity": 1746690000
}

Error responses:

CodeErrorCause
404 Not Foundcard_not_foundNo registered card with this cardId

POST /api/cards/:cardId/topup

Add balance to a card. Requires the Station to be online; no offline top-up is permitted.

Request headers: Authorization: Bearer <station-token>

Request body:

{
"amount": 100000,
"operatorId": 7,
"timestamp": 1746700000
}

Response (200 OK):

{
"cardId": "<6-byte hex>",
"balanceBefore": 350000,
"balanceAfter": 450000,
"amount": 100000,
"timestamp": 1746700000
}

Error responses:

CodeErrorCause
403 Forbiddeninsufficient_roleCaller is not a station
404 Not Foundcard_not_foundCard not registered
422 Unprocessable Entitybalance_ceiling_exceededbalanceAfter would exceed maxBalance
422 Unprocessable Entitycard_blockedCard is in any blocked status; top-up is not allowed

POST /api/cards/:cardId/block

Administratively block a card. Sets status to BLOCKED_ADMIN on the backend record. The Station app must then write the updated status to the physical card.

Request headers: Authorization: Bearer <station-token>

Request body:

{
"reason": "lost",
"operatorId": 7,
"timestamp": 1746701000
}

reason must be one of: lost, stolen, fraud, decommission.

Response (200 OK):

{
"cardId": "<6-byte hex>",
"status": "BLOCKED_ADMIN",
"blockedAt": 1746701000,
"reason": "lost"
}

Error responses:

CodeErrorCause
403 Forbiddeninsufficient_roleCaller is not a station
404 Not Foundcard_not_foundCard not registered
409 Conflictalready_blockedCard is already in a blocked status

POST /api/cards/:cardId/reissue

Authorise a blocked card for re-issuance. The backend marks the card as clearable and issues a station session grant with the reissue operation. The Station app must physically re-write the card payload.

Re-issuance for BLOCKED_TAMPER and BLOCKED_FRAUD requires explicit backend authorization. See Tech Specs §15.

Request headers: Authorization: Bearer <station-token>

Request body:

{
"operatorId": 7,
"authCode": "<one-time backend-issued authorisation code>",
"timestamp": 1746702000
}

Response (200 OK):

{
"cardId": "<6-byte hex>",
"reissueGranted": true,
"newKeyVersion": 4,
"timestamp": 1746702000
}

Error responses:

CodeErrorCause
403 Forbiddeninsufficient_roleCaller is not a station
403 Forbiddenreissue_not_authorisedBackend authorisation code missing or expired
404 Not Foundcard_not_foundCard not registered
422 Unprocessable Entitycard_not_blockedCard is ACTIVE; reissue is not applicable