API Reference
Detailed information about endpoints, parameters, and responses.
API Documentation
Accept payments programmatically: create payment sessions, share checkout links with your customers, and receive signed webhooks when money moves.
Getting started
The API is served from https://api.trite.tech. Create an API key in the dashboard under Settings → Integrations → API Management.
Format Info
25.50) with an ISO currency code.Authentication
Pass your key as a bearer token on every request. Your merchant account is derived from the key — there is no merchant ID parameter.
Authorization: Bearer trite_sk_...Keep your API key secure
401. The full key is shown exactly once at creation — store it securely. Keys look like trite_sk_… and can be revoked at any time. Never use your API key in browser or mobile code — server-side only.Merchant verification
The direct charge endpoints move money on a payer's behalf, so they require your merchant account to be fully verified. This means:
- Email verified — confirm your email address via the link sent at registration.
- KYC approved — submit identity verification documents in the merchant portal under Settings and receive approval.
If either requirement is not met, those calls return 403 with a machine-readable code field:
{
"error": "Merchant account email is not verified. Please verify your email in the merchant portal.",
"code": "EMAIL_NOT_VERIFIED"
}{
"error": "Merchant KYC verification is required. Please complete identity verification in the merchant portal.",
"code": "KYC_NOT_APPROVED",
"kyc_status": "PENDING"
}KYC Status Values
kyc_status field will be one of: PENDING, IN_REVIEW, APPROVED, REJECTED, EXPIRED, or null (no KYC record submitted yet). Only APPROVED grants API access.Create a payment session
Creates a checkout session and returns a payment_url to hand to your customer. Sessions expire after 24 hours.
curl https://api.trite.tech/api/v1/payments/initiate \
-H "Authorization: Bearer trite_sk_..." \
-H "Content-Type: application/json" \
-d '{
"amount": 25.50,
"currency": "GHS",
"description": "Order #1234",
"redirect_url": "https://yourstore.com/thank-you",
"customer_email": "ama@example.com",
"customer_name": "Ama Serwaa",
"customer_phone": "0244123456"
}'{
"session_id": "3f6b1c9e-...",
"payment_url": "https://pay.trite.tech/pay/3f6b1c9e-...",
"amount": 25.5,
"currency": "GHS",
"expires_at": "2026-07-08T12:00:00.000Z"
}A session created without customer_email or customer_phone still succeeds, with a warnings array in the response. Treat those warnings as errors in waiting.
| Field | Type | Notes |
|---|---|---|
| amount | number | Required. Positive, major units. |
| currency | string | Optional, default USD. |
| description | string | Optional, shown at checkout. |
| redirect_url | string | Optional, payer is sent here after payment. |
| customer_email | string | Who is paying. Will become required — sessions without it are accepted for now and return a warning. Identifies the payer in your customer directory, and is the only identity we get on crypto payments. |
| customer_name | string | Optional. Shown in your customer directory. |
| customer_phone | string | Optional. Local or international format. Prefills the mobile money field at checkout, and is the strongest way to recognise a returning payer. |
400 invalid input, 401 bad key, 403 merchant is not currently accepting payments, 429 rate limited, 500 server error.Check session status
Returns the session and its latest transaction. Prefer webhooks over polling for real-time updates.
curl https://api.trite.tech/api/v1/payments/3f6b1c9e-.../status \
-H "Authorization: Bearer trite_sk_..."{
"session_id": "3f6b1c9e-...",
"status": "COMPLETED",
"amount": 25.5,
"currency": "GHS",
"description": "Order #1234",
"expires_at": "2026-07-08T12:00:00.000Z",
"created_at": "2026-07-07T12:00:00.000Z",
"transaction": {
"transaction_id": "9a2d...",
"tx_id_display": "TX-8F3K2M",
"status": "SETTLED",
"method": "MOBILE_MONEY",
"amount": 25.5,
"currency": "GHS",
"failure_reason": null
}
}404.Direct charge
Debit a mobile money wallet from your own backend, with no Trite-hosted checkout page. The payer approves the charge on their handset. Ghana mobile money only — GHS is the only supported currency.
curl https://api.trite.tech/api/v1/payments/charge \
-H "Authorization: Bearer trite_sk_..." \
-H "Content-Type: application/json" \
-d '{
"amount": 200,
"mobile_number": "0249713683",
"provider": "MTN",
"currency": "GHS",
"description": "Order #1234"
}'{
"reference": "TX-8F3K2M-A1B2C3D4",
"transaction_id": "9a2d...",
"session_id": "3f6b1c9e-...",
"status": "INITIATED",
"amount": 200,
"currency": "GHS",
"message": "Payment prompt sent to your phone. Please approve it."
}| Field | Type | Notes |
|---|---|---|
| amount | number | Required. Positive, major units — 200 means GHS 200.00. |
| mobile_number | string | Required. The payer's mobile money number. |
| provider | string | Required. MTN, TELECEL, or AT. Not inferred from the number — a ported line would charge the wrong network. |
| currency | string | Optional, default GHS. No other value is accepted. |
| description | string | Optional, shown on the payer's prompt where the network supports it. |
| payer_email | string | Optional. Recorded against the transaction and added to your customer directory once the charge settles. |
| payer_name | string | Optional. Names the payer in your customer directory instead of showing a bare phone number. |
| status | HTTP | What to do |
|---|---|---|
| INITIATED | 202 | The prompt is on the payer's handset. Wait for your webhook. |
| OTP_REQUIRED | 202 | Collect the OTP the payer was texted and submit it below. |
| FAILED | 422 | The charge was rejected outright. message says why. |
When a charge returns OTP_REQUIRED, submit the code against the same reference. The response uses the shapes above.
curl https://api.trite.tech/api/v1/payments/charge/submit-otp \
-H "Authorization: Bearer trite_sk_..." \
-H "Content-Type: application/json" \
-d '{
"reference": "TX-8F3K2M-A1B2C3D4",
"otp": "123456"
}'To read a charge's current state, use its reference. Terminal states are SETTLED and FAILED.
curl https://api.trite.tech/api/v1/payments/charge/TX-8F3K2M-A1B2C3D4 \
-H "Authorization: Bearer trite_sk_..."{
"reference": "TX-8F3K2M-A1B2C3D4",
"transaction_id": "9a2d...",
"session_id": "3f6b1c9e-...",
"status": "SETTLED",
"amount": 200,
"currency": "GHS",
"method": "MOBILE_MONEY",
"failure_reason": null,
"created_at": "2026-08-09T14:21:07.412Z",
"updated_at": "2026-08-09T14:21:44.907Z"
}status is INITIATED while the payer still has the prompt, then SETTLED or FAILED. failure_reason is populated only on the latter.
Prefer webhooks over polling
tx_id_display as your reference. If you do poll, poll every 3–5 seconds and stop after about five minutes.404. Submitting an OTP against a charge that is no longer awaiting one returns 409.Webhooks
Configure your endpoint URL and event subscriptions in Settings → Integrations → Webhook Configuration. Events are delivered as POST requests with a JSON envelope:
{
"id": "evt_5c1a...",
"type": "payment.success",
"created_at": "2026-07-07T12:03:41.000Z",
"data": {
"tx_id_display": "TX-8F3K2M",
"session_id": "3f6b1c9e-...",
"amount": 25.5,
"currency": "GHS",
"method": "MOBILE_MONEY",
"status": "SETTLED"
}
}| Event | Fires when |
|---|---|
| payment.success | A payment settles (funds credited to your balance). |
| payment.failed | A payment fails or expires. data.failure_reason explains why. |
| payout.success | A settlement to your payout account completes. |
| payout.failed | A settlement is declined; funds return to your balance. |
Webhook Delivery Retry
Verifying signatures
Every delivery carries an X-Trite-Signature header: t=<unix>,v1=<hex>. Compute HMAC-SHA256 of `${t}.${rawBody}` with your signing secret (Settings → Integrations), compare timing-safely, and reject if the timestamp is more than 5 minutes old.
import crypto from "crypto";
function verifyTriteSignature(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(
header.split(",").map((p) => p.split("="))
);
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}Rate limits
Limits are per merchant, per bucket, in a fixed one-minute window. Exceeding one returns 429 with a Retry-After header (seconds). Back off and retry after that interval.
| Bucket | Limit | Endpoints |
|---|---|---|
| v1/payments | 60/min | Create session, check session status |
| v1/payments/charge | 60/min | Direct charge, submit OTP |
| v1/payments/charge:status | 300/min | Read a charge by reference — a polling loop can never starve your charge bucket |
Deprecations
Endpoint Deprecation
POST /api/payments/initiate is a deprecated alias of POST /api/v1/payments/initiate and now requires the same API-key authentication. Migrate to the v1 path; a removal date will be announced in advance.SDKs
SDKs & Libraries
We're working on official libraries for Node.js, Python, PHP, and more.