Core concepts
Conventions
Rules every endpoint follows. Read them once before you build.
Requests#
- JSON in and out (
Content-Type: application/json), UTF-8. The only exceptions are the token route (form-encoded) and bordereaux (CSV out). - Unknown body fields and query parameters are rejected (
400 bad_request), so typos fail loudly instead of being ignored. - Bodies are limited to 100 KB.
| Header | Direction | Use |
|---|---|---|
Authorization | request | Bearer <accessToken> on every route except the token route. |
Idempotency-Key | request | Safe retries of writes. See below. |
If-Match | request | The version you read, to avoid overwriting a newer change. See below. |
X-Request-Id | both | Your id for the call (a fresh UUID), echoed in the response and our logs. |
ETag | response | Version of an editable resource: W/"7". |
RateLimit, RateLimit-Policy, Retry-After | response | Rate limiter state. See Rate limits. |
Response envelope#
Every JSON response, success or error, has the same four keys:
200 OK
{
"status": "success",
"data": { "id": "6f1c2d3e-4b5a-4c69-8d7e-1f2a3b4c5d6e", "status": "active" },
"error": null,
"metadata": {
"timestamp": "2026-11-05T09:15:02.481Z",
"path": "/api/v1/partner/policies/6f1c2d3e-4b5a-4c69-8d7e-1f2a3b4c5d6e",
"method": "GET",
"requestId": "8d7e2c1a-41f0-4a4e-9a55-6f0b3c2d1e77"
}
}statusissuccess(2xx),fail(4xx: fix the request) orerror(5xx: our side, retry later).- Read the HTTP status code and
error.code. Never parseerror.message: it's English text for developers and can change. See Errors. metadata.requestIdidentifies the call. Log it and quote it to support.
Data formats#
| Kind | Format | Example |
|---|---|---|
| Ids | UUID strings. Path ids that aren't UUIDs get 400. | 6f1c2d3e-4b5a-4c69-8d7e-1f2a3b4c5d6e |
| Money | EGP, decimal strings with 2 decimals. Prices are tax-inclusive. | "9500.00", "-620.27" |
| Instants | ISO 8601 in UTC. | 2026-11-05T09:15:02.481Z |
| Calendar dates | YYYY-MM-DD, on the Cairo (Africa/Cairo) calendar. | 2026-11-05 |
| Phone numbers | Egyptian mobiles, returned as 01XXXXXXXXX. | 01012345678 |
| Translatable text | Both languages, always. | { "en": "Gold Care", "ar": "جولد كير" } |
| Enums | Lowercase snake_case, case-sensitive. | documents_requested |
Parse money with a decimal type (decimal in C#, Decimal in Python, BigDecimal in Java, a decimal library in JavaScript). Never with a binary float: rounding errors break reconciliation.
Pagination#
Lists take page (from 1) and size (1–100, default 20) and return:
data
{
"items": [ { "id": "…" } ],
"meta": {
"page": 2,
"size": 20,
"totalItems": 47,
"totalPages": 3,
"hasNextPage": true,
"hasPreviousPage": true
}
}Change feed#
Policies, cancellations, claims and packages accept updatedSince. Sorted by updatedAt ascending, a list is a change feed: a reliable way to sync, and the safety net behind webhooks.
Pseudocode
# Every few minutes, per resource:
since = load_checkpoint("policies") # e.g. 2026-11-04T00:00:00.000Z
loop:
page = GET /partner/policies?updatedSince={since}&sortBy=updatedAt&sortOrder=asc&size=100
for row in page.items:
upsert(row) unless already_seen(row.id, row.updatedAt)
if page.items: since = page.items[-1].updatedAt; save_checkpoint("policies", since)
if not page.meta.hasNextPage: breakRows changed in the same millisecond can appear on two pages, so make the upsert idempotent on id + updatedAt.
Idempotency#
A network failure can hide whether a write happened. Send Idempotency-Key: <UUID v4> on writes; if you retry with the same key, the action runs once and every retry gets the first result.
- One key per action (one cancellation, one approval), reused for every retry of it. A new action gets a new key.
- Successful results are kept for 24 hours.
- A failed request (validation or business error) releases the key, so you can fix the input and retry with the same key.
| Status | Code | Meaning | Do |
|---|---|---|---|
| 409 | idempotency_request_is_still_processing | The first request with this key is still running. | Wait Retry-After (1 s), retry with the same key. |
| 422 | idempotency_key_already_used | Same key, different URL or body. | Bug: use a new key for a new action. |
| 400 | bad_request | Key missing where required, or not 8–128 of A-Z a-z 0-9 _ -. | Send a UUID v4. |
Each endpoint shows whether it requires or supports the header. Required on money-moving actions (cancel a policy, record a refund).
Concurrent edits#
Your staff may edit the same resource in the Wathiqaty portal while your system does through the API. Editable resources return a version in ETag (and a version field). Send it back as If-Match: if someone changed the resource since you read it, you get 412 version_conflict with details.currentVersion instead of silently overwriting their change. Reload, re-apply, resend.
Files#
Files are never streamed through the API. Responses carry a url to download from directly. To upload (settlement proof), ask for a presigned upload URL, send the file straight to storage, then reference its fileKey.
Personal data#
Policies carry the policyholder's personal data, including the national id verified by eKYC. Request policies:read only for systems that need it, store only what your policy administration requires, and handle it under Egypt's Personal Data Protection Law (151/2020) and the integration agreement.