Dokumentasyon para sa developers
Lahat ng kailangan mo para tumanggap ng USDT payments gamit ang Kem Business API: authentication, ang payments endpoints, at signed webhooks na nagpapatakbo ng estado ng order mo.
Authentication
Gumawa ng API keys sa dashboard sa ilalim ng «API keys», at ipadala ang secret key bilang Bearer token sa bawat request. Ang test keys (sk_test_…) ay gumagawa ng test payments; ang live keys (sk_live_…) ay naggagalaw ng totoong pera.
Authorization: Bearer sk_live_... # or sk_test_...
Base URL: https://api-business.kemapp.ioPayments
Gumawa ng payment at dalhin ang customer sa hosted checkout_url nito — si Kem ang bahala sa wallets, networks at confirmations. Subaybayan ang estado sa pag-fetch ng payment o, mas mainam, sa webhooks.
/v1/paymentscurl -X POST https://api-business.kemapp.io/v1/payments \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042" \
-d '{
"amount": "25.000000",
"currency": "USDT",
"merchant_reference": "order-1042",
"customer_email": "[email protected]",
"description": "Pro plan",
"return_url": "https://yourshop.example/thanks",
"metadata": {"order_id": "1042"}
}'{
"id": "pay_01J...",
"status": "pending",
"mode": "test",
"amount": "25.000000",
"amount_minor": 25000000,
"currency": "USDT",
"merchant_reference": "order-1042",
"checkout_url": "https://pay.kemapp.io/pay_01J...",
"checkout_expires_at": "2026-07-13T13:30:00+00:00",
"created_at": "2026-07-13T13:00:00+00:00"
}Idempotency-Key — opsyonal pero inirerekomenda — ang retry gamit ang parehong key ay nagbabalik ng orihinal na payment sa halip na gumawa ng duplicate.
/v1/payments— query: status, limit (1–100, default 20), cursor · returns has_more, next_cursor/v1/payments/{id}amount — decimal string with 6 places ("25.000000"); amount_minor — the same value as an integer in micro-USDT.
Lifecycle ng payment
pending → detected → succeeded · failed · expired
pending — hinihintay ang transfer · detected — nakita on-chain, kinukumpirma · succeeded — kumpirmado ang pondo sa wallet mo (dito i-fulfill) · failed / expired — pinal. Ang refund ay dumarating bilang webhook events.
checkout window: 30 minutes, then → expired
Mga error at limitasyon
Iisang envelope ang lahat ng error. Stable ang mga code — mag-branch sa error.code, hindi sa mensahe.
HTTP 4xx/5xx
{
"error": {
"code": "idempotency_conflict",
"message": "Idempotency-Key reused with a different request"
}
}| 401 unauthorized | missing or invalid API key |
| 404 not_found | unknown payment id (or a live id with a test key) |
| 409 idempotency_conflict | Idempotency-Key reused with a different body — identical retries replay the original response |
| 422 (validation) | malformed body — bad amount, unsupported currency |
| 429 rate_limited | over the per-key budget: 100 writes/min, 1000 reads/min |
Ang products, payment links, webhook endpoints at refunds ay pinamamahalaan mula sa dashboard — wala pa silang pampublikong REST endpoints.
Webhooks
Magdagdag ng endpoint sa dashboard sa ilalim ng «Webhooks» at piliin ang mga event na mahalaga sa iyo. Bawat endpoint ay may sariling whsec_… signing secret, ipinapakita nang isang beses sa paggawa.
| payment.created | A payment intent was created (API or checkout link). |
| payment.detected | The transfer was seen on-chain / in the KEM ledger; confirming. |
| payment.succeeded | Funds are confirmed in your business wallet. Fulfill on this event. |
| payment.failed | The payment failed. |
| payment.expired | The checkout window closed without payment. |
| payment.refund.created | A refund was initiated from the dashboard. |
| payment.refund.succeeded | The refund settled back to the customer. |
Event payload
{
"id": "payment_event_01J...",
"type": "payment.succeeded",
"created": "2026-07-13T13:04:12+00:00",
"data": {
"payment": {
"id": "pay_01J...",
"status": "succeeded",
"amount_minor": 25000000,
"currency": "USDT",
"merchant_reference": "order-1042",
"network": "TRON",
"product_id": null,
"payment_link_id": null
}
}
}Pag-verify ng signatures
Bawat delivery ay may Kem-Signature header. I-recompute ang HMAC sa «<t>.» kasama ang raw request body gamit ang endpoint secret mo, at ikumpara nang constant time. Tanggihan ang hindi tumutugma.
Kem-Signature: t=<unix_timestamp>,v1=<hmac_sha256_hex>
signed_input = "<t>." + raw_request_body
v1 = HMAC_SHA256(endpoint_secret, signed_input) # secret: whsec_...
# reject replays: drop the delivery when |now - t| > 300simport crypto from "node:crypto";
export function verifyKemSignature(rawBody, header, secret) {
// header: "t=1720000000,v1=hex"
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const expected = crypto
.createHmac("sha256", secret) // secret: whsec_...
.update(`${parts.t}.`)
.update(rawBody) // the RAW request bytes
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}import hashlib, hmac
def verify_kem_signature(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=") for p in header.split(","))
expected = hmac.new(
secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, parts["v1"])Delivery at retries
Sumagot ng 2xx nang mabilis. Ang mga bigong delivery ay ire-retry nang may backoff, pagkatapos ay ide-dead-letter:
1m · 5m · 30m · 2h · 12h · 24h
Pagsubok
Gamit ang test key, mapapatakbo mo ang payment sa buong lifecycle nang walang perang gumagalaw — i-simulate ang transitions at panoorin ang webhooks mo:
curl -X POST https://api-business.kemapp.io/v1/payments/{id}/_simulate/succeeded \
-H "Authorization: Bearer sk_test_..."