Skip to main content

6. Reconciliation

Terminals accumulate offline events during connectivity gaps. When connectivity is restored, the terminal submits a reconciliation batch. The backend validates each event against policy limits and persists them to the audit log.

Financial limit enforcement rules: Tech Specs §9. Transaction log format: Tech Specs §14.


POST /api/reconcile

Upload a batch of offline terminal events.

Request headers: Authorization: Bearer <terminal-token>

Request body:

{
"terminalId": 42,
"events": [
{
"cardId": "<6-byte hex>",
"counter": 17,
"type": "debit",
"amount": 15000,
"balanceAfter": 485000,
"timestamp": 1746690000,
"hash": "<6-byte truncated chain hash, hex>"
}
]
}
FieldTypeDescription
terminalIduint16Identifies the submitting terminal
eventsarrayOrdered list of card events (earliest first)
events[].cardIdhex string6-byte card identifier
events[].counteruint64Monotonic write counter at the time of this event
events[].typestringdebit, credit, checkin, checkout, admin
events[].amountuint32Transaction amount in IDR (0 for non-financial events)
events[].balanceAfteruint32Card balance after this event
events[].timestampuint32UTC seconds when the event occurred
events[].hashhex string6-byte truncated chain hash from the card log entry

Response (200 OK):

{
"accepted": 3,
"rejected": 1,
"flags": [
{
"counter": 18,
"cardId": "<hex>",
"reason": "daily_limit_exceeded"
}
]
}
FieldDescription
acceptedNumber of events accepted and logged
rejectedNumber of events that failed validation (duplicate, tamper, malformed)
flagsEvents accepted but flagged for review (limit breach, suspicious pattern)

Non-flagged events within policy are accepted silently. Flagged events are logged and surfaced to the reconciliation operator.

Error responses:

CodeErrorCause
400 Bad Requestmalformed_payloadRequest body missing required fields or wrong types
401 Unauthorizedinvalid_tokenBearer token missing or invalid
409 Conflictduplicate_counterAn event with the same cardId + counter was already reconciled

Rejection vs flagging

ConditionOutcome
Duplicate cardId + counterRejected (not logged again)
Hash mismatch against known chainRejected; tamper event auto-reported
Balance inconsistencyRejected
Daily limit exceededAccepted + flagged
Weekly limit exceededAccepted + flagged
amount > singleTxLimitRejected (should have been blocked at terminal)

Ordering

Events within a batch must be ordered by counter ascending. If events for multiple cards are mixed in one batch, the backend processes them in the order received.