Skip to main content
Create a checkout session for a critical escrow action. The session allows you to redirect a specific user to dhmad.tn to perform the action (e.g., sign contract, accept & pay, complete, dispute, or handle cancellation). The user is redirected back to your redirectUrl after completing or abandoning the flow. The API validates that the action is still needed before creating a session. If the action is already done (e.g. the target user has already signed the contract, or payment is already completed), the request returns 400 with a structured error (error.code, error.user_message). Use these to show a clear message in your app instead of redirecting to checkout.
Configure allowed redirect URLs in your Developer Dashboard settings before creating checkout sessions. If no redirect URLs are configured, or if the redirectUrl does not match any allowed URL, the request will fail with a 400 error.
curl -X POST https://dhmad.tn/api/v1/escrows/507f1f77bcf86cd799439011/sessions \
  -H "Authorization: Bearer sk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "sign_contract",
    "targetUserEmail": "buyer@example.com",
    "redirectUrl": "https://myapp.com/checkout/callback",
    "metadata": {
      "order_id": "ord_123"
    }
  }'
{
  "sessionId": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://dhmad.tn/checkout/550e8400-e29b-41d4-a716-446655440000",
  "expiresAt": "2024-01-15T10:30:00Z"
}

Path Parameters

id
string
required
Escrow ID

Request Body

action
string
required
The action the user will perform. Must be one of: sign_contract, accept_pay, complete, dispute, request_cancellation, reject_cancellation, accept_cancellation, cancel_escrow, submit_proof, review_proof. If the action is already done (e.g. contract already signed, payment already made), the API returns 400 with a business rule error—see Error Responses below.Cancellation actions (paid or delivered escrows):
  • request_cancellationBuyer only. Target the buyer’s email. The buyer cannot cancel unilaterally after payment; they request cancellation and the seller must accept or reject.
  • cancel_escrowSeller only. Target the seller’s email. Cancels immediately and refunds the buyer when applicable.
  • reject_cancellation / accept_cancellation — Target the seller’s email (counterparty of the buyer who requested). Create these only after a pending cancellation request exists.
  • Targeting the wrong party returns 400 (CANCELLATION_REQUEST_BUYER_ONLY, CANCEL_ESCROW_SELLER_ONLY, or CHECKOUT_TARGET_NOT_BUYER / CHECKOUT_TARGET_NOT_SELLER).
By escrow mode:
  • standard — all actions apply when status allows (except proof actions).
  • quick — no contract; sign_contract returns 400 (QUICK_ESCROW_NO_CONTRACT). Use accept_pay then complete. With Quick Escrow with Proof, use submit_proof (seller) and review_proof (buyer) while proofInfo.phase requires them.
  • instant — only accept_pay (and dispute/cancellation actions) are valid; sign_contract, complete, and proof actions return 400.
targetUserEmail
string
required
Email of the user who will perform the action. Only this user can complete the session.
redirectUrl
string
required
URL to redirect the user after they complete or abandon the flow. Must match one of your allowed redirect URLs configured in the developer dashboard. Must use HTTPS (except http://localhost for development).
metadata
object
Optional key-value pairs (strings only). Useful for tracking orders or internal references. Values must be 500 characters or less.

Response Fields

No KYC check is performed when creating a checkout session. You can create an accept_pay session regardless of the buyer’s KYC status. If the buyer does not have approved KYC, they will be prompted to complete identity verification inside the DHMAD checkout flow (inline Verify KYC) before they can complete Accept & Pay. You do not receive a separate error code for KYC at session creation time.

Error Responses

When a request is rejected because of a business rule (e.g. the action is already done, or redirect URL is invalid), the API returns 400 Bad Request with an error object. Use error.code to branch in your app and error.user_message to show a clear message to the end user; error.message is for developers and logging. The table below lists all error codes returned by this endpoint. Business rule error shape (400)
{
  "error": {
    "code": "CONTRACT_ALREADY_SIGNED",
    "type": "business_rule_violation",
    "message": "Cannot create checkout session: this signer has already signed the contract.",
    "user_message": "This contract has already been signed."
  }
}
CodeWhen
NO_REDIRECT_URLS_CONFIGUREDDeveloper has no allowed redirect URLs in dashboard settings.
REDIRECT_URL_NOT_ALLOWEDredirectUrl does not match any allowed redirect URL.
REDIRECT_URL_MUST_BE_HTTPSredirectUrl is not HTTPS (except http://localhost).
INSTANT_ESCROW_NO_CONTRACTAction is sign_contract but escrow is instant (no contract). Use accept_pay instead.
INSTANT_ESCROW_NO_COMPLETE_STEPAction is complete but escrow is instant; completion happens via deliver endpoint.
QUICK_ESCROW_NO_CONTRACTAction is sign_contract but escrow is quick (no contract). Use accept_pay instead.
CONTRACT_ALREADY_SIGNEDAction is sign_contract and the target user has already signed the contract.
PAYMENT_ALREADY_DONEAction is accept_pay but the escrow is already paid, delivered, or completed.
ESCROW_ALREADY_COMPLETEDAction is complete but the escrow is already completed.
DISPUTE_ALREADY_OPENEDAction is dispute but a dispute has already been opened.
CANCELLATION_REQUEST_INVALID_STATUSAction is request_cancellation but escrow is not paid or delivered.
CANCELLATION_REQUEST_BUYER_ONLYAction is request_cancellation but targetUserEmail is the seller. Use cancel_escrow instead.
CANCEL_ESCROW_INVALID_STATUSAction is cancel_escrow but escrow is not paid or delivered.
CANCEL_ESCROW_SELLER_ONLYAction is cancel_escrow but targetUserEmail is the buyer. Use request_cancellation instead.
CHECKOUT_TARGET_NOT_BUYERAction is request_cancellation (or another buyer-only action) but targetUserEmail is not the buyer.
CHECKOUT_TARGET_NOT_SELLERAction is cancel_escrow (or another seller-only action) but targetUserEmail is not the seller.
CANCELLATION_ALREADY_REQUESTEDAction is request_cancellation but a cancellation has already been requested or processed.
NO_PENDING_CANCELLATIONAction is reject_cancellation or accept_cancellation but there is no pending cancellation request.
Example: contract already signed
{
  "error": {
    "code": "CONTRACT_ALREADY_SIGNED",
    "type": "business_rule_violation",
    "message": "Cannot create checkout session: this signer has already signed the contract.",
    "user_message": "This contract has already been signed."
  }
}
Example: payment already done
{
  "error": {
    "code": "PAYMENT_ALREADY_DONE",
    "type": "business_rule_violation",
    "message": "Cannot create checkout session: payment has already been made for this escrow.",
    "user_message": "Payment has already been completed for this transaction."
  }
}
Handle these in your app by checking response.error?.code and displaying response.error?.user_message to the user instead of redirecting to checkout.

401 Unauthorized

{
  "error": "Unauthorized"
}

403 Forbidden

{
  "error": "Forbidden",
  "message": "You do not have access to this escrow."
}

404 Not Found

Escrow Not Found
{
  "error": "Escrow not found"
}
Developer Not Found
{
  "error": "Developer not found"
}

Sessions expire 30 minutes after creation. Ensure users complete the flow within this window, or create a new session if needed.
For escrows created with mode: "instant", only the accept_pay action (and dispute/cancellation actions) is valid. Do not use sign_contract or complete; they will return 400. After the buyer pays, deliver the digital goods and call Deliver Escrow to auto-complete and release funds.