Checkout Sessions Integration Guide
Checkout Sessions let you redirect users to dhmad.tn to perform critical escrow actions—signing contracts, accepting payments, completing deliveries, opening disputes, or handling cancellations—without building these flows yourself. This guide walks you through the full integration.Introduction
When your application needs a user to perform an escrow action that requires DHMAD’s hosted UI (e.g., contract signing, payment, proof upload/review, completion), you:- Create a checkout session via the API
- Redirect the user to the session URL
- The user completes the action on dhmad.tn
- DHMAD redirects the user back to your app with the result
Step-by-Step Integration
Step 1: Configure Allowed Redirect URLs
Before creating any checkout sessions, add your redirect URLs in the Developer Dashboard under Settings. Only URLs in this list will be accepted asredirectUrl when creating sessions.
Examples:
https://myapp.com/checkout/callbackhttps://myapp.com/escrow/completehttp://localhost:3000/callback(for local development)
Step 2: Create a Checkout Session via API
CallPOST /api/v1/escrows/:id/sessions with:
- action — The action type (e.g.,
sign_contract,accept_pay,submit_proof,review_proof,complete) - targetUserEmail — Email of the user who will perform the action
- redirectUrl — Your callback URL (must match an allowed URL)
- metadata (optional) — Key-value pairs for your own tracking
sessionId, url, and expiresAt. Redirect the user to url.
If the action is already done (e.g. the user has already signed the contract, or payment is already completed), the API returns 400 with an error object: error.code, error.message (for developers), and error.user_message (for end users). Check error.type === 'business_rule_violation' and display error.user_message in your UI instead of redirecting to checkout. See Create Checkout Session for all error codes.
Step 3: Redirect the User to the Session URL
Send the user to theurl returned from the create session call. For example:
Step 4: Handle the Redirect Callback
When the user finishes (or abandons) the flow, DHMAD redirects them to yourredirectUrl with query parameters:
session_id— The session IDstatus— One of:completed,expired,cancelled
GET /api/v1/sessions/:sessionId to verify and get full session details.
What happens inside checkout
The checkout page shows a summary of the escrow: amount, platform service fee (DHMAD’s fee, paid by the seller), and, if the escrow was created with a developer fee, the application / app fee (with your app name when configured). Both fees are deducted from the seller’s payout.Instant escrows — guest payment (accept_pay, no DHMAD login)
For escrows created with mode: "instant" and a checkout session action accept_pay, if the buyer is not logged into DHMAD they can pay without creating an account. They pick a payment method (e.g. bank transfer, D17, Flouci, PayPal), complete the payment using the instructions shown, and upload a proof file. An admin must approve the proof; only then does the escrow move to paid and your app should rely on escrow.status.updated (and related webhooks) as usual.
- Funds are not held in a DHMAD buyer wallet for this path until the proof is approved; cancellation and refunds follow DHMAD’s guest-checkout rules (your app should not assume an automatic wallet refund to the buyer).
- Sandbox: the flow may complete without a proof file for faster testing.
- Seller cancellation before approval: pending proofs for that escrow are closed automatically; you may receive
escrow.deposit_proof.rejected(with a system reason) andescrow.status.updatedwhen the escrow becomescancelled. The checkout session may be markedcancelled. Treat webhooks as the source of truth, not only the browser redirect.
Standard flow (logged-in buyer or non-instant escrow)
When the user is on dhmad.tn/checkout and completes Accept and pay under the standard path (e.g. standard escrow mode, or the buyer is signed in and uses the wallet flow), DHMAD may require them to complete additional steps before the action succeeds:- Email or phone verification: If the buyer has not verified their email or phone, they see an inline popup on the same page to enter the verification code (OTP). We send the code when the popup opens; after they enter it and verify, they can click Confirm & Pay again. No redirect to profile.
- KYC (identity verification): If the buyer has not completed KYC, they see an inline Verify identity (KYC) block on the same page. They can start verification (opens in a new tab); after completing it, they return to the checkout page and can click Confirm & Pay again. No redirect away from checkout.
- Insufficient balance: If the buyer’s balance is too low, they see an inline top-up option on the same page. After topping up, they click Confirm & Pay again.
redirectUrl with session_id and status when they complete the action, cancel, or the session expires. You do not receive error codes (e.g. KYC_REQUIRED) in your redirect callback—those cases are handled entirely on DHMAD.
For all error codes returned when creating a session (e.g. contract already signed, payment already done, SELLER_NOT_READY when the seller has not completed pre-account identity verification), see Create Checkout Session — Error Responses.
Step 5: Verify with Webhooks
Treat webhooks as the source of truth. When a user completes an action via a Checkout Session, DHMAD emits webhooks for the underlying events (e.g.,contract.signed, escrow.paid, escrow.completed). Use webhooks to update your backend state; use the redirect for immediate UI feedback.
Complete Code Example (Node.js / Express)
Security Best Practices
Validate Redirect Params
When handling the callback, validate that
session_id matches a session you created. Don’t trust arbitrary query params.Use Webhooks
Always process webhooks for escrow state changes. Redirect params are for UX; webhooks are for backend truth.
HTTPS in Production
Use HTTPS for all redirect URLs in production. Never use
http:// except for localhost during development.Protect API Keys
Keep API keys server-side only. Never expose them in client-side code or public repositories.
FAQ
What happens if the session expires?
Sessions expire 30 minutes after creation. If the user does not complete the flow in time, they will be redirected withstatus=expired. Create a new session and redirect the user again if needed.
Can I create multiple sessions for the same escrow?
Yes. You can create multiple sessions for different actions or for retries. Each session has a uniquesessionId and is single-use.
Can the same user complete multiple sessions?
Yes. Each session is independent. A user can complete one session (e.g., sign contract) and later complete another (e.g., accept & pay) for the same escrow.What if the user closes the browser before completing?
If the user abandons the flow, they may be redirected withstatus=cancelled or may not reach your callback at all. Handle both cases in your UI. The session remains pending until it expires or is completed.
Do I need to handle the redirect if I use webhooks?
Yes. The redirect provides immediate feedback to the user (e.g., “Payment successful”). Webhooks update your backend. Use both: redirect for UX, webhooks for data integrity.Can I use checkout sessions in sandbox mode?
Yes. Use your sandbox API key (sk_sandbox_*) and the sandbox base URL. The checkout URL will point to the sandbox frontend (e.g., https://sandbox.dhmad.tn/checkout/:sessionId).
What about instant escrows (digital goods)?
For escrows created withmode: "instant" (e.g. in-app coins, AI credits), use only the accept_pay action. The buyer pays in one step; there is no contract to sign and no “complete” step. After the buyer pays, you receive a webhook, deliver the goods, then call the Deliver Escrow API—the escrow auto-completes and funds are released. See Escrow Modes — Instant in the Escrows overview.
What about quick escrows (products without a contract)?
For escrows created withmode: "quick" (e.g. physical or digital products between two users), use accept_pay then complete after the seller delivers. There is no contract to sign — sign_contract returns 400. See Escrow Modes — Quick in the Escrows overview.
What about Quick Escrow with Proof?
When you setfulfillmentPolicy.type: "purchase_proof_required" at creation, add submit_proof (seller uploads after pay) and review_proof (buyer accepts or requests corrections) before the seller can deliver. Fetch proof files with GET /escrows/:id/proof. See the Quick Escrow with Proof guide.
How do paid or delivered cancellation checkout sessions work?
After payment, buyers cannot cancel unilaterally. Use checkout sessions as follows:request_cancellation— Target the buyer’s email. Escrow must bepaidordelivered.cancel_escrow— Target the seller’s email. Escrow must bepaidordelivered. Cancels immediately and refunds the buyer when applicable.accept_cancellationorreject_cancellation— After the buyer requests, target the seller’s email so they can accept (refund) or reject.
request_cancellation or the buyer for cancel_escrow returns 400.
For escrows still in pending status (before payment), use Cancel Escrow instead — both parties can cancel via the API.
For API reference details, see Create Checkout Session and Get Checkout Session.