YOUR NEXT INTEGRATION STARTS HERE
Good data.
Great things to build.
Bring Sudan’s bank availability, telecom status, and currency rates into your product. Find your first request, explore the endpoints, and connect to change events.
- BASE URL
https://status.sd/api/open/v1- FORMAT
- JSON
- CONTRACT
- OpenAPI 3.1
Your API at a glance
Download OpenAPI01 · GET STARTED
First request #
Use a server-side environment and replace the placeholder with a key created in your developer dashboard.
curl "https://status.sd/api/open/v1/dashboard" \
-H "X-API-Key: sk_live_..." \
-H "Accept: application/json"02 · AUTHENTICATION
Keep credentials on the server #
Send your key using either X-API-Key or Authorization: Bearer sk_live_.... If both headers are sent, they must contain the same key. Never expose a live key in a browser or mobile application.
sk_live_ + 48 alphanumeric characters03 · RESILIENCE
Errors and limits #
Successful requests include X-RateLimit-Limit and X-RateLimit-Remaining. Back off when you receive 429 and honor Retry-After when present.
| Status | Code | What to do |
|---|---|---|
| 401 | invalid_api_key | Check the key, header, and whether the key was revoked. |
| 402 | subscription_required | Activate or renew the developer subscription. |
| 422 | Validation errors | Correct the named request fields before retrying. |
| 429 | rate_limit_exceeded | Wait for Retry-After, then retry with jitter. |
| 429 | quota_exhausted | Wait until resets_at or change plans. |
| 503 | Temporarily unavailable | Retry later with exponential backoff. |
04 · API REFERENCE
Endpoints
All endpoints require authentication. Select a response code to inspect its exact sample body.
Status dashboard
Returns the current status of every bank and telecom plus public app configuration. Responses are cached for 60 seconds and include an ETag.
Parameters 1
| Name | Location | Required | Description |
|---|---|---|---|
If-None-Match | header | No | ETag from a previous response. |
Request
curl "https://status.sd/api/open/v1/dashboard" \
-H "X-API-Key: sk_live_..." \
-H "Accept: application/json"Responses
Current dashboard snapshot.
{
"updated_at": "2026-11-08T18:42:11.000000Z",
"banks": [
{
"slug": "bank-of-khartoum",
"name_ar": "بنك الخرطوم",
"name_en": "Bank of Khartoum",
"logo_url": "https://status.sd/storage/banks/bok.png",
"since": "2026-11-08T18:42:11.000000Z",
"app_status": "working",
"android": "working",
"ios": "working",
"internal_transfer": "working",
"zain_recharge": "unstable",
"sudani_recharge": "working",
"mtn_recharge": "working",
"electricity": "working",
"interbank_transfer": "down",
"international_transfer": null,
"subscriber_services": "working",
"device_change": "working"
}
],
"telecoms": [
{
"slug": "zain",
"name_ar": "زين",
"name_en": "Zain",
"call": "working",
"internet": "unstable",
"recharge": "working",
"since": "2026-11-08T17:00:00.000000Z"
}
],
"app": {
"website_url": "https://status.sd",
"android_url": "https://play.google.com/store/apps/details?id=sd.status",
"ios_url": ""
}
}Bank status history
Returns newest-first status intervals that started today (UTC) for one bank. Older records are never exposed by the developer API.
Parameters 4
| Name | Location | Required | Description |
|---|---|---|---|
slug | path | Yes | The bank's stable slug. |
page | query | No | |
per_page | query | No | Items per page. Do not combine with `limit`. |
limit | query | No | Alias for `per_page`. Do not combine both. |
Request
curl "https://status.sd/api/open/v1/banks/bank-of-khartoum/history" \
-H "X-API-Key: sk_live_..." \
-H "Accept: application/json"Responses
A simple-paginated list of status intervals.
{
"data": [
{
"slug": "bank-of-khartoum",
"name_ar": "بنك الخرطوم",
"name_en": "Bank of Khartoum",
"logo_url": "https://status.sd/storage/banks/bok.png",
"notification_topic": "bank_of_khartoum",
"since": "2026-11-08T18:42:11.000000Z",
"app_status": "working",
"android": "working",
"ios": "working",
"internal_transfer": "working",
"zain_recharge": "unstable",
"sudani_recharge": "working",
"mtn_recharge": "working",
"electricity": "working",
"interbank_transfer": "down",
"international_transfer": null,
"subscriber_services": "working",
"device_change": "working",
"started_at": "2026-11-08T18:42:11.000000Z",
"ended_at": null
}
],
"links": {
"first": "https://status.sd/api/open/v1/banks/bank-of-khartoum/history?page=1",
"next": null,
"prev": null
},
"meta": {
"current_page": 1,
"from": 1,
"path": "https://status.sd/api/open/v1/banks/bank-of-khartoum/history",
"per_page": 50,
"to": 1
}
}Currency and gold snapshot
Returns the latest bank and parallel-market rates, movement direction, and the latest gold price when available.
Request
curl "https://status.sd/api/open/v1/currency" \
-H "X-API-Key: sk_live_..." \
-H "Accept: application/json"Responses
Latest currency and gold data.
{
"fetched_at": "2026-11-08T18:42:11.000000Z",
"source_updated_at": "2026-11-08T18:40:00.000000Z",
"last_checked_at": "2026-11-08T18:42:11.000000Z",
"rates": [
{
"name": "US Dollar",
"symbol": "$",
"code": "USD",
"bank_rate": 601.5,
"parallel_rate": 2480,
"bank_direction": "stable",
"parallel_direction": "up",
"details_url": "https://status.sd/currency/usd"
}
],
"gold": {
"price": 168500,
"previous_price": 167000,
"quoted_on": "2026-11-08",
"fetched_at": "2026-11-08T18:42:11.000000Z",
"last_checked_at": "2026-11-08T18:42:11.000000Z"
}
}Webhook events
Lists every event code that can be selected on a developer webhook.
Request
curl "https://status.sd/api/open/v1/events" \
-H "X-API-Key: sk_live_..." \
-H "Accept: application/json"Responses
Supported event codes.
{
"data": [
{
"code": "bank.status.changed",
"description": "A bank service status changed."
},
{
"code": "currency.updated",
"description": "Currency rates were updated."
}
]
}05 · WEBHOOKS
Updates delivered to you #
Nabd sends a JSON POST and considers any 2xx response successful. Connections time out after 5 seconds and requests after 10 seconds. Redirects are not followed.
- NowAttempt 1
- +60 secAttempt 2
- +5 minAttempt 3
- +30 minFinal attempt
X-StatusSD-Delivery to handle duplicate deliveries safely. Do not assume events arrive immediately or in order.bank.status.changed#Sent whenever one or more service statuses for a bank change.
Delivery headers 4
| Header | Purpose |
|---|---|
X-StatusSD-Event | Event code, such as bank.status.changed |
X-StatusSD-Delivery | Unique delivery ID; use it for deduplication |
X-StatusSD-Timestamp | Unix timestamp included in the signature input |
X-StatusSD-Signature | HMAC-SHA256 signature prefixed by sha256= |
Example payload
{
"id": 18431,
"event": "bank.status.changed",
"created_at": "2026-11-08T18:42:11+00:00",
"data": {
"bank": {
"id": 1,
"slug": "bank-of-khartoum",
"name_ar": "بنك الخرطوم",
"name_en": "Bank of Khartoum"
},
"statuses": {
"app_status": "working",
"android": "working",
"ios": "working",
"internal_transfer": "working",
"zain_recharge": "unstable",
"sudani_recharge": "working",
"mtn_recharge": "working",
"electricity": "working",
"interbank_transfer": "down",
"international_transfer": null,
"subscriber_services": "working",
"device_change": "working"
},
"changed_at": "2026-11-08T18:42:11.000000Z"
}
}currency.updated#Sent after a new currency snapshot is stored.
Delivery headers 4
| Header | Purpose |
|---|---|
X-StatusSD-Event | Event code, such as bank.status.changed |
X-StatusSD-Delivery | Unique delivery ID; use it for deduplication |
X-StatusSD-Timestamp | Unix timestamp included in the signature input |
X-StatusSD-Signature | HMAC-SHA256 signature prefixed by sha256= |
Example payload
{
"id": 18432,
"event": "currency.updated",
"created_at": "2026-11-08T18:45:00+00:00",
"data": {
"snapshot_id": 924,
"fetched_at": "2026-11-08T18:45:00.000000Z",
"source_updated_at": "2026-11-08T18:40:00.000000Z",
"rates": [
{
"code": "USD",
"bank_rate": 601.5,
"parallel_rate": 2480
}
]
}
}06 · SECURITY
Verify every signature #
Build the signed value from the exact raw request bytes: timestamp + "." + rawBody. Calculate HMAC-SHA256 with the webhook secret and compare the complete sha256=... value in constant time.
import crypto from "node:crypto";
function verifyWebhook(rawBody, timestamp, signature, secret) {
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(timestamp + "." + rawBody)
.digest("hex");
const actualBuffer = Buffer.from(signature);
const expectedBuffer = Buffer.from(expected);
return actualBuffer.length === expectedBuffer.length &&
crypto.timingSafeEqual(actualBuffer, expectedBuffer);
}