Skip to content

Award endpoint

POST  /v1/ep/webhook

FieldTypeRequiredRules
tenantIdstringyesMust be one of your allowedTenants.
orderIdstringyes1–200 chars. Unique per award on your side. Drives idempotency.
userEmailstringyesValid email. Normalized to lowercase on our side.
amountintegeryesPositive raw amount (e.g. order value). Converted to EP — see below.
notestringno≤ 500 chars. Shown in the user’s EP history.
metaobjectnoFree-form key/values stored on the ledger entry for your auditing.
{
"tenantId": "7g1RP3",
"orderId": "order-2026-0001",
"userEmail": "user@example.com",
"amount": 50000,
"note": "Order #2026-0001 cashback",
"meta": { "campaign": "summer-sale", "channel": "pos" }
}

EP credited is floored at a fixed rate of 1000 raw units = 1 EP:

points = floor(amount / 1000)
amountEP creditedResult
5000050OK
15001OK
9990Rejected — 422 AMOUNT_BELOW_MIN

Send amount ≥ 1000. A sub-rate amount credits 0 EP and is rejected rather than recorded as a no-op. The raw amount and the rate are stored on the ledger entry (rawAmount, amountPerEp) so the conversion is auditable.

All caps are checked against the credited EP (points), not the raw amount:

CapMeaningOn exceed
perTxMax EP in a single award.422 PER_TX_CAP_EXCEEDED
perPartnerDayMax EP you may award (per tenant) in one day.429 DAILY_CAP_EXCEEDED
perUserDayMax EP one user may receive (per tenant, across all partners) per day.429 DAILY_CAP_EXCEEDED

The “day” window is the Vietnam day (UTC+7) — daily counters reset at midnight Vietnam time.

A fresh award returns 202 Accepted:

{
"epTransactionId": "ep_tx_01HX...",
"status": "COMPLETED",
"orderId": "order-2026-0001",
"points": 50
}

A replay of the same orderId with the same payload returns 200 OK with code: "DUPLICATE" (no double credit):

{
"epTransactionId": "ep_tx_01HX...",
"status": "COMPLETED",
"points": 50,
"code": "DUPLICATE"
}

See Idempotency & retries for the full contract, and the error contract for every failure code.