02 - End-to-End Integration Flow
The definitive path from first register to live in the Super App, plus
the two runtime systems every partner touches: orders (fulfillment) and
signed webhooks (event delivery).
See also:
- Getting Started -- quick-start onboarding checklist
- Authentication & Team -- registration, login, tokens, and team management
1. Full lifecycle
flowchart TD
R[POST /register] --> OTP[Verify OTP]
OTP --> Login[POST /auth/login + verify-otp]
Login --> Company[PATCH /company + upload docs<br/>CR / TAX / REP_ID]
Company --> Ready{GET /company/readiness<br/>canSubmitVerification?}
Ready -->|no| Company
Ready -->|yes| Submit[POST /company/submit]
Submit --> Ver[Admin review<br/>UNDER_REVIEW / APPROVED]
Ver -->|INFO_REQUIRED / REJECTED| Company
Ver -->|APPROVED| App[POST /applications<br/>integrationModel EMBEDDED]
App --> Listing[PATCH /listing + offers + panels]
Listing --> ListSub[POST /listing/submit]
ListSub --> AdminList[Admin decision<br/>APPROVED / CHANGES_REQUESTED]
AdminList -->|CHANGES_REQUESTED| Listing
AdminList -->|APPROVED / PUBLISHED| Live[Customers buy in Super App<br/>POST /marketplace/purchase]
Live --> WH[Partner receives webhooks]
Phase gates
2. Stage-by-stage walkthrough
Stage A — Onboarding (Days 0–1)
Readiness response:
{
"organizationStatus": "ONBOARDING",
"verificationStatus": "DRAFT",
"profileIncomplete": true,
"missingFields": ["bankName: is required", "iban: is required"],
"missingDocuments": ["REP_ID"],
"canSubmitVerification": false,
"canCreateApplication": false,
"canPublishListing": false
}Status enums — organization & verification
| Event | Org status | Verification status |
|---|---|---|
| Register | ONBOARDING | DRAFT |
| Submit KYC | PENDING_VERIFICATION | SUBMITTED |
| Admin review | PENDING_VERIFICATION | UNDER_REVIEW |
| Admin approve | APPROVED | APPROVED |
| Admin reject | REJECTED | REJECTED |
| Admin suspend | SUSPENDED | SUSPENDED |
Once org =
APPROVEDyou can create an application.
Stage B — Build the service (Days 2–5)
POST /developer-portal/applications→ DRAFT application
(integrationModel: "EMBEDDED").PATCH /developer-portal/applications/:id— setwebsiteUrl,
redirectUrls,allowedWebOrigins,partnerApiBaseUrl,supportContact.POST .../credentials/sandbox/generate— raw key shown once.PATCH .../listingthen add offers/panels.POST .../listing/submit→ listingSUBMITTED.
Offers payload
{
"titleEn": "Silver top-up",
"titleAr": "تعبئة فضية",
"descriptionEn": "Instant digital top-up",
"design": "banner",
"linkType": "offer",
"url": "https://partner.acme.sa/buy/silver",
"price": "49.99",
"originalPrice": "79.99",
"currency": "SAR",
"inStock": true,
"perUserLimit": 5,
"badgeLabel": "Best seller",
"badgeColor": "#E8553C",
"fulfillmentMode": "INSTANT"
}Offer price is a decimal string (≤ 7 integer + 2 fraction digits); titles are
capped at 200 chars; a listing holds at most 20 offer cards. For composing
panels, card styles, and layout recipes, see
Panels & storefront.
Fulfillment modes
flowchart LR
Charge[Card charged] --> Mode{fulfillmentMode}
Mode -->|INSTANT| Done[Order COMPLETED immediately]
Mode -->|PARTNER_CONFIRMATION| Pending[Order PENDING_PARTNER_CONFIRM]
Pending -->|partner confirm->start->complete| Done
- INSTANT — order completes immediately (
PAYMENT_AUTHORIZED → COMPLETED). - PARTNER_CONFIRMATION — you drive fulfillment via
POST .../orders/:orderId/{confirm|start|complete|cancel}
(PAYMENT_AUTHORIZED → PENDING_PARTNER_CONFIRM → CONFIRMED → IN_PROGRESS → COMPLETED).
Stage C — Go live (Day 6)
- Ensure your webhook endpoint is configured and tested in sandbox.
- Listing is
PUBLISHED→ customers can purchase in the Super App. - Monitor order webhooks and fulfill via confirmation endpoints if needed.
3. The purchase moment (customer side)
sequenceDiagram
autonumber
participant C as Customer (Super App)
participant M as DigetPay /v1/marketplace
participant G as Card gateway
participant P as Partner endpoint
C->>M: POST /marketplace/purchase { offerId, savedMethodId, pin }
M->>G: recurringCharge (vault token / saved method)
M-->>C: 201 order { status, fulfillmentMode, fulfillment }
M-->>P: webhook payment.created
par INSTANT path
M-->>P: webhook order.completed
M-->>C: fulfillment (deeplink or webview+launch token)
and PARTNER_CONFIRMATION path
M-->>P: webhook order.confirmation_required
P-->>M: POST .../orders/:id/confirm
P-->>M: POST .../orders/:id/start
P-->>M: POST .../orders/:id/complete
M-->>C: fulfillment becomes available
end
- Purchases are idempotent via the
x-idempotency-keyheader — a replayed
key returns the original order instead of charging twice. - If the wallet PIN is missing, the API returns
401 PIN_REQUIREDso the app
shows the PIN sheet and retries withpin.
Settlement — the developer's net
$$ S_{net} = price_{unit} \times qty - fee_{processing} $$
where S_{net} is the amount settled to your payout account, qty is paid
units, and fee_{processing} is DigetPay's processing fee. Settlement events
arrive as webhook settlement.completed.
Order status enum
| Status | Meaning |
|---|---|
CREATED | Draft order row created |
PENDING_PAYMENT | Charge initiated against the card |
PAYMENT_AUTHORIZED | Charge captured, awaiting fulfillment |
PENDING_PARTNER_CONFIRM | Waiting for partner confirm |
CONFIRMED | Partner acknowledged the order |
IN_PROGRESS | Partner is fulfilling (start) |
COMPLETED | Fulfilled (complete) / instant |
CANCELLED | Partner cancelled |
FAILED | Payment failed / expired |
REFUND_PENDING / REFUNDED | Refund underway / completed |
4. Orders endpoints
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /developer-portal/applications/:id/orders | Marketplace orders for your app |
| GET | /developer-portal/applications/:id/transactions | Same data as a sales ledger |
| POST | /developer-portal/applications/:id/orders/:orderId/:action | Advance an order |
4.1 List application orders
curl -X GET \
"https://fin-api.digetpay.com/v1/developer-portal/applications/42/orders?page=1&pageSize=25&status=COMPLETED" \
-H "Authorization: Bearer $ACCESS_TOKEN"Response 200 — { items, meta }
{
"id": "1024",
"status": "COMPLETED",
"fulfillmentStatus": "COMPLETED",
"fulfillmentMode": "INSTANT",
"offer": { "offerId": "12", "titleEn": "Silver top-up", "price": "49.99", "currency": "SAR", "quantity": 1 },
"fulfillment": { "type": "deeplink", "url": "https://partner.acme.sa/redeem/7f3a…", "token": null, "allowedOrigins": [] },
"createdAt": "2026-08-18T10:04:12.000Z"
}4.2 Advance an order (partner-confirmation models)
curl -X POST \
"https://fin-api.digetpay.com/v1/developer-portal/applications/42/orders/1024/complete" \
-H "Authorization: Bearer $ACCESS_TOKEN"| Action | Meaning | Allowed from |
|---|---|---|
confirm | Accept the order | PENDING_PARTNER_CONFIRM |
start | Begin fulfillment | CONFIRMED |
complete | Finish fulfillment | IN_PROGRESS |
cancel | Cancel (money refund flows separately) | PENDING_PARTNER_CONFIRM |
canceldoes not itself move money back. Refunds are driven by the refund
workflow / gateway and surface via thepayment.refundedwebhook.
Order actions are validated transitions — an illegal transition returns
400.
Take the order status from the webhook, not from a local cache.
5. Webhook endpoints
| Method | Endpoint | Purpose |
|---|---|---|
| GET | .../applications/:appId/webhooks/catalog | Read the event catalog |
| GET | .../applications/:appId/webhooks | List endpoints |
| POST | .../applications/:appId/webhooks | Create an endpoint |
| PATCH | .../applications/:appId/webhooks/:endpointId | Update URL/events/active |
| DELETE | .../applications/:appId/webhooks/:endpointId | Remove an endpoint |
| POST | .../applications/:appId/webhooks/:endpointId/test | Send a signed test delivery |
| GET | .../applications/:appId/webhooks/deliveries | Delivery log for an app |
5.1 Create an endpoint
{
"environment": "SANDBOX",
"url": "https://api.acme.sa/webhooks/digetpay",
"events": ["payment.completed", "order.completed"],
"retryLimit": 3
}environment∈SANDBOX | PRODUCTIONurlmust be httpsevents≤ 20, chosen from the catalog belowretryLimit∈ 1–5 (default 3)
5.2 Event catalog
| Event | Raised when |
|---|---|
application.approved | Company verification approved |
application.rejected | Verification rejected |
payment.created | Card charge initiated |
payment.completed | Charge captured |
payment.failed | Charge declined / failed |
payment.refunded | Refund finalized |
order.confirmation_required | Waiting for partner confirm |
order.confirmed | Partner confirmed |
order.in_progress | Partner started fulfillment |
order.completed | Fulfillment complete (or INSTANT) |
order.cancelled | Order cancelled |
order.expired | Order auto-expired |
order.failed | Order failed |
service.completed | End-service milestone completed |
settlement.completed | A settlement batch was paid out |
webhook.connection_test | Endpoint /test button (not subscribable) |
6. Delivery envelope & signatures
Every delivery is a POST (10 s timeout) with JSON body:
{
"event": "payment.completed",
"environment": "SANDBOX",
"applicationId": "42",
"createdAt": "2026-08-18T10:04:12.000Z",
"data": { "orderId": "1024", "amount": "49.99", "currency": "SAR" }
}The outer fields (event, environment, applicationId, createdAt) are
always present; the business object lives in data. Prefer the
X-DigetPay-Event header for routing and the event body field for
verification.
Signature construction
$$ signature = \text{HMAC-SHA256}(webhookSecret,\ timestamp_{sec}\ .\ rawBody) $$
Headers every delivery carry:
| Header | Example value |
|---|---|
Content-Type | application/json |
User-Agent | DigetPay-Webhooks/1.0 |
X-DigetPay-Timestamp | 1784544252 (Unix seconds) |
X-DigetPay-Signature | sha256=… (hex HMAC over {ts}.{rawBody}) |
X-DigetPay-Event | payment.completed |
# Recompute the expected signature on your side
TS="1784544252"
BODY='{"event":"payment.completed","environment":"SANDBOX",...}'
EXPECTED="sha256=$(printf '%s.%s' "$TS" "$BODY" \
| openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}')"
[ "$EXPECTED" = "$DIGETPAY_SIGNATURE" ] && echo "verified" || echo "reject"Verify the signature and check
X-DigetPay-Timestampis fresh (e.g. within
±5 minutes) before trusting any payload.
The webhook is signed with the application's webhook secret, not the API
key. Rotate it viaPOST .../credentials/{env}/rotate-webhook-secret.
Retry & backoff policy
| Attempt | Wait before next | Trigger |
|---|---|---|
| Any | — | success = HTTP 2xx |
| 1st | ~250 ms | network error, 429, 5xx |
| 2nd | ~500 ms | same |
| 3rd | ~1 s | same |
| 4th | ~2 s | same |
| last | stop | failure logged to deliveries |
retryLimitcaps attempts at 1–5 (default 3).- Non-retryable
4xxresponses (e.g.400) are not retried. - Every attempt is recorded in the deliveries log with
httpStatus,attempts,
lastError, andsuccess.
Endpoint test
POST .../webhooks/:endpointId/test sends a one-shot webhook.connection_test
delivery with data.message = "DigetPay webhook connection test" (no retries)
and returns { httpStatus, success, errorMessage }.
Sample payloads
7. Deliveries log
GET .../webhooks/deliveries?page=1&pageSize=25 returns delivery attempts:
| Field | Type | Meaning |
|---|---|---|
endpointId | string | Webhook endpoint that received it |
eventType | string | Delivered event |
httpStatus | number? | Last HTTP status (null = network error) |
success | boolean | Whether the last attempt was 2xx |
attempts | integer | How many attempts were made |
lastError | string? | Last failure reason |
Use the deliveries log to debug silent misses — check that
events[]
subscription,active, andretryLimitall look right first.
8. Testing flow (staging walkthrough)
- Register → login → dashboard shows
ONBOARDING - Company profile + CR/TAX/REP uploads → readiness clears → submit
SUBMITTED - Admin
APPROVED→ create application (gate removed) - Sandbox credentials generated (raw key captured once)
- Webhook endpoint created +
/testreturns signed delivery - Listing submitted → admin
APPROVED/PUBLISHED - Customer purchase →
payment.completed+order.completed
9. Go-live checklist
- Endpoint created for
PRODUCTIONwith the full event set you rely on -
X-DigetPay-Signatureverified on staging - Timestamp freshness (+/-5 min) enforced
- Retry handling + deliveries monitoring in place
-
payment.refundedhandled (money can always come back) - Order
PARTNER_CONFIRMATIONactions tested throughcomplete
Orders + signed webhooks cover the runtime contract. Integration is complete
once your endpoint verifies signatures and your fulfillment actions move orders
toCOMPLETED.
Updated about 1 month ago

