Getting Started
Integrate Ethiopian Transaction Verification
Create an API key, submit a verification, then choose whether your app waits briefly, polls for completion, streams status with SSE, or receives the result through a webhook.
Choose an Integration Flow
Create an API Key
- 1
Sign in
Open/loginand authenticate with your account. - 2
Create a key
Open the dashboard API keys area, create a key, and save the fullVERIFY_BANK_ET_your_key_heresecret immediately. It is shown once. - 3
Set permissions
For verification flows, includeverification:writeto submit requests andverification:readto poll, stream, or read history. - 4
Send the header
Addx-api-keyto every API request. AddIdempotency-Keyto safely retry submissions.
Credits are account-level
429 and 402 responses as recoverable integration states.Verify.ET Agent Skill is here
Let your AI agent integrate Verify.ET and ship to production automatically. No docs. No manual setup. Just add your API key in your .env and let the agent handle the rest.
npx skills add NegusNati/verify-et-apiWorks with
Use the Production Endpoint
Verify.ET is provided through the hosted verify.et domain. These examples intentionally use the same base URL your production integration uses.
VERIFY_ET_BASE_URL=https://verify.et
VERIFY_ET_API_KEY=VERIFY_BANK_ET_your_key_hereSubmit Your First Verification
POST /api/verify accepts explicit bank payloads and universal smart-router payloads. Identifier fields may include full SMS text or supported receipt URLs; the server best-effort normalizes them when confident (explicit bank is never re-routed). Prefer clean fields in production. waitMs asks the API to wait briefly for a terminal result, but the server caps the wait time per bank.
curl -X POST \
"https://verify.et/api/verify?waitMs=5000" \
-H "Content-Type: application/json" \
-H "x-api-key: $VERIFY_ET_API_KEY" \
-H "Idempotency-Key: verify-demo-001" \
-d '{
"bank": "cbe",
"referenceNumber": "FT1234567890",
"accountSuffix": "12345678"
}'Handle both 200 and 202
200 response includes the completed verification. A 202 response means the request is queued and includes a status URL you can poll or stream.{
"success": true,
"message": "Verification queued.",
"data": [],
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"statusUrl": "/api/verify/550e8400-e29b-41d4-a716-446655440000",
"estimatedWaitMs": 5000,
"verification": {
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"bank": "cbe",
"processingStatus": "queued",
"status": "pending",
"verified": false
},
"links": {
"statusUrl": "/api/verify/550e8400-e29b-41d4-a716-446655440000",
"pollAfterMs": 1500
}
}Poll or Stream Status
Poll GET /api/verify/:requestId until processingStatus is completed or failed. For near real-time updates, open the SSE endpoint.
const baseUrl = process.env.VERIFY_ET_BASE_URL ?? "https://verify.et";
const requestId = process.env.VERIFY_ET_REQUEST_ID!;
const statusUrl = `${baseUrl}/api/verify/${encodeURIComponent(requestId)}`;
for (let attempt = 0; attempt < 20; attempt += 1) {
const response = await fetch(statusUrl, {
headers: { "x-api-key": process.env.VERIFY_ET_API_KEY! },
});
const body = await response.json();
const status = body.data?.processingStatus;
if (status === "completed" || status === "failed") {
return body.data;
}
await new Promise((resolve) => setTimeout(resolve, body.links?.pollAfterMs ?? 1500));
}
throw new Error("Verification did not finish before polling timeout.");VERIFY_ET_BASE_URL="https://verify.et"
VERIFY_ET_REQUEST_ID="replace-with-the-request-id-from-submit"
curl -N \
-H "Accept: text/event-stream" \
-H "x-api-key: $VERIFY_ET_API_KEY" \
"$VERIFY_ET_BASE_URL/api/verify/$VERIFY_ET_REQUEST_ID/events"SSE event names
status events as the row changes, then a done event with reason terminal or timeout.Receive Results With Webhooks
Pass webhookUrl in the JSON body or X-Webhook-Url as a header. When the verification finishes, the worker sends verification.completed to your endpoint.
curl -X POST \
"https://verify.et/api/verify" \
-H "Content-Type: application/json" \
-H "x-api-key: $VERIFY_ET_API_KEY" \
-H "X-Webhook-Url: https://your-app.com/webhooks/verify" \
-d '{
"bank": "telebirr",
"transactionNumber": "TELE123456"
}'URL Validation
Production URLs must use HTTPS, must not include credentials, and must resolve to public addresses.
Delivery Headers
Expect X-Webhook-Event, X-Webhook-Timestamp, X-Webhook-Delivery-Id, and optional X-Webhook-Signature.
Retries
Default delivery policy retries up to 5 attempts: immediate, 30s, 2m, 8m, then 30m.
Signature verification
${X-Webhook-Timestamp}.${rawJsonBody} and compare it with X-Webhook-Signature in the format sha256=<hex>.Bank Fields
Use universal fields when you want the router to detect the provider. Use explicit bank fields when your checkout already knows the bank or wallet.
Universal Payload
| Field | Required | Description |
|---|---|---|
| bank | Optional | Optional for universal routing. Use it when you already know the provider and want strict validation. |
| reference | Optional | Universal input. Can map to a bank reference, transaction number, receipt number, URL, or token. |
| suffix | Optional | Universal account suffix. Use 8 digits for CBE or 5 digits for Bank of Abyssinia. |
| phoneNumber | Optional | Universal CBE Birr phone. Accepts 09XXXXXXXX or 251XXXXXXXXX and normalizes to 251XXXXXXXXX. |
| webhookUrl | Optional | Callback URL for result delivery. In production it must be public HTTPS and must not resolve to private or reserved IP space. |
Explicit Bank Payloads
| Field | Required | Description |
|---|---|---|
| cbe | Required | Use referenceNumber/reference plus accountSuffix/suffix exactly 8 digits. |
| boa | Required | Use referenceNumber/reference plus accountSuffix/suffix exactly 5 digits. |
| telebirr | Required | Use transactionNumber or reference. |
| mpesa | Required | Use transactionNumber or reference. Receipt URLs and supported SMS text can be parsed. |
| cbebirr | Required | Use receiptNumber/reference plus phone/phoneNumber. |
| dashen / awash / siinqee | Required | Use referenceNumber or reference. |
| kaafiebirr | Required | Use referenceNumber/reference. phone/phoneNumber is optional. |
CBERequires referenceNumber and an 8-digit accountSuffix.
curl -X POST \
"https://verify.et/api/verify?waitMs=5000" \
-H "Content-Type: application/json" \
-H "x-api-key: $VERIFY_ET_API_KEY" \
-d '{
"bank": "cbe",
"referenceNumber": "FT1234567890",
"accountSuffix": "12345678"
}'
Bank of AbyssiniaRequires referenceNumber and a 5-digit accountSuffix.
curl -X POST \
"https://verify.et/api/verify?waitMs=5000" \
-H "Content-Type: application/json" \
-H "x-api-key: $VERIFY_ET_API_KEY" \
-d '{
"bank": "boa",
"referenceNumber": "BOA123456789",
"accountSuffix": "12345"
}'
TelebirrRequires transactionNumber or reference.
curl -X POST \
"https://verify.et/api/verify?waitMs=5000" \
-H "Content-Type: application/json" \
-H "x-api-key: $VERIFY_ET_API_KEY" \
-d '{
"bank": "telebirr",
"transactionNumber": "TELE123456"
}'
MPESAAccepts a transaction number, reference, supported receipt URL, or supported SMS text.
curl -X POST \
"https://verify.et/api/verify?waitMs=5000" \
-H "Content-Type: application/json" \
-H "x-api-key: $VERIFY_ET_API_KEY" \
-d '{
"bank": "mpesa",
"transactionNumber": "MPESA123456"
}'
CBE BirrRequires receiptNumber plus phone or phoneNumber.
curl -X POST \
"https://verify.et/api/verify?waitMs=5000" \
-H "Content-Type: application/json" \
-H "x-api-key: $VERIFY_ET_API_KEY" \
-d '{
"bank": "cbebirr",
"receiptNumber": "CBE-BIRR-123456",
"phone": "0911223344"
}'
DashenRequires referenceNumber or reference.
curl -X POST \
"https://verify.et/api/verify?waitMs=5000" \
-H "Content-Type: application/json" \
-H "x-api-key: $VERIFY_ET_API_KEY" \
-d '{
"bank": "dashen",
"referenceNumber": "DASHEN123456"
}'
AwashRequires referenceNumber or reference.
curl -X POST \
"https://verify.et/api/verify?waitMs=5000" \
-H "Content-Type: application/json" \
-H "x-api-key: $VERIFY_ET_API_KEY" \
-d '{
"bank": "awash",
"referenceNumber": "AWASH123456"
}'
SiinqeeRequires referenceNumber or reference.
curl -X POST \
"https://verify.et/api/verify?waitMs=5000" \
-H "Content-Type: application/json" \
-H "x-api-key: $VERIFY_ET_API_KEY" \
-d '{
"bank": "siinqee",
"referenceNumber": "SIINQEE123456"
}'
Kaafi EbirrRequires referenceNumber or reference.phone is optional.
curl -X POST \
"https://verify.et/api/verify?waitMs=5000" \
-H "Content-Type: application/json" \
-H "x-api-key: $VERIFY_ET_API_KEY" \
-d '{
"bank": "kaafiebirr",
"referenceNumber": "https://receipt.ebirr.com/kaafimf/ilgi8ctn1Tr6vhw_so79kw"
}'Current support note
zemen appears in status and bank enums, but direct POST /api/verify submissions for Zemen are not supported yet.Next up
API Reference
The full reference includes exact response envelopes, endpoint permissions, rate-limit behavior, and copyable request examples for each supported integration path.
View REST examples by language