Contracts API

Contracts API Reference

Create contracts with milestones and parties, and read them back.

Overview

These are the partner routes under /api/external/contracts: create a contract, add milestones and parties, and read contracts back. A "complex" contract is a parent whose milestones are child contracts. Authenticate as described in Authentication. The calls for a whole payment, step by step, are under Build a payment.

POSTCreate Contract

Create a new complex contract that can contain multiple milestones

Endpoint

POST /api/external/contracts

Request Body

{
  "type": "COMPLEX_CONTRACT",
  "senderRole": "BROKER",
  "itemDetail": {
    "title": "example title",
    "description": "example description",
    "images": [
      "image url1",
      "image url2"
    ]
  },
  "returnPolicy": "NO_RETURN",
  "returnFeePayee": "PROVIDER",
  "waffyTermsAccepted": true,
  "category": "Services"
}

Sender Role Values

PROVIDER,CUSTOMER,BROKER

Response (201 Created)

{
  "status": 201,
  "timestamp": "2026-01-21T17:00:01.408195",
  "data": {
    "id": "6971061074385b2c31672af3",
    "version": 0,
    "shortId": "UEVlKJpT",
    "type": "COMPLEX_CONTRACT",
    "senderId": "12345678",
    "senderRole": "BROKER",
    "itemDetail": {
      "title": "example title",
      "description": "example description",
      "images": [
        "image url1",
        "image url2"
      ]
    },
    "itemPrice": 0.0,
    "totalAmount": 0.0,
    "currency": null,
    "status": "CREATED",
    "createdAt": "2026-01-21T17:00:00.724+00:00",
    "contractClassification": "BASIC",
    "isParent": true,
    "parties": [
      {
        "userId": "12345678",
        "role": "BROKER",
        "phoneNumber": "+966559555555",
        "isSender": true,
        "arbitrator": true
      }
    ],
    "category": "Services",
    "organization": {
      "organizationCode": "merchant_organization_code",
      "accountId": 1234
    }
  }
}

PATCHAdd Milestones

Add milestone sub-contracts to the main contract

Endpoint

PATCH /api/external/contracts/6971061074385b2c31672af3/milestones
Note:The contract ID in the URL parameter is the parent complex contract ID returned from the "Create Contract" API.

Request Body

{
  "milestones": [
    {
      "type": "MILESTONE_CONTRACT",
      "senderRole": "PROVIDER",
      "itemDetail": {
        "title": "first milestone example title",
        "description": "first milestone example description"
      },
      "itemPrice": 100000,
      "currency": "SAR",
      "returnPolicy": "NO_RETURN",
      "returnFeePayee": "PROVIDER",
      "deadLine": "2024-10-28T10:34:57.536Z",
      "waffyTermsAccepted": true,
      "addOnFees": [
        {
          "amount": 10,
          "description": "Extra 10% Amount",
          "beneficiary": "+966559555555",
          "payee": "+966555444444",
          "type": "EXTRA_AMOUNT",
          "feeType": "FLAT"
        }
      ]
    }
  ]
}

AddOn Fee Types

SHIPPING_FEES,SERVICE_FEES,EXTRA_AMOUNT,PLATFORM_COMMISSION,PAYMENT_FEES

Response (200 OK)

{
  "status": 200,
  "timestamp": "2026-01-21T17:07:02.599251",
  "data": {
    "parentContractId": "6971061074385b2c31672af3",
    "milestones": [
      {
        "id": "697107b674385b2c31672af5",
        "shortId": "pUZB9kCK",
        "type": "MILESTONE_CONTRACT",
        "senderRole": "BROKER",
        "receiverRole": "CUSTOMER",
        "itemDetail": {
          "title": "first milestone example title",
          "description": "first milestone example description"
        },
        "itemPrice": 100000.0,
        "fee": 4000.0,
        "feePercentage": 0.04,
        "totalAmount": 104000.0,
        "currency": "SAR",
        "status": "CREATED",
        "isParent": false,
        "parentId": "6971061074385b2c31672af3",
        "deadLine": "2024-10-28T10:34:57.536+00:00",
        "addonFeesList": [
          {
            "amount": 10.0,
            "feeType": "FLAT",
            "description": "Extra 10% Amount",
            "beneficiary": "+966559555555",
            "payee": "+966555444444",
            "type": "EXTRA_AMOUNT"
          }
        ]
      }
    ]
  }
}

PATCHAdd Parties

Add parties to milestone contracts with roles and amounts

Endpoint

PATCH /api/external/contracts/6971061074385b2c31672af3/parties
Note:The contract ID in the URL is the parent contract created in the first request. The map keys in the request body (e.g., "697107b674385b2c31672af5") are the milestone IDs created in the "Add Milestones" API.

Request Body

{
  "mileStonesParties": {
    "697107b674385b2c31672af5": [
      {
        "phoneNumber": "+966555444444",
        "role": "CUSTOMER",
        "amount": 100000
      },
      {
        "phoneNumber": "+966559555555",
        "role": "BROKER",
        "amount": 99100,
        "arbitrator": true
      },
      {
        "phoneNumber": "+966555444445",
        "role": "PROVIDER",
        "amount": 910,
        "isSender": true
      }
    ]
  }
}

Response (200 OK)

{
  "status": 200,
  "timestamp": "2026-01-21T17:12:02.474103",
  "data": {
    "id": "6971061074385b2c31672af3",
    "type": "COMPLEX_CONTRACT",
    "status": "CREATED",
    "parties": [
      {
        "userId": "12345678",
        "role": "BROKER",
        "phoneNumber": "+966559555555",
        "amount": 99100,
        "arbitrator": true
      },
      {
        "userId": "23456789",
        "role": "CUSTOMER",
        "phoneNumber": "+966555444444",
        "amount": 100000
      },
      {
        "userId": "34567891",
        "role": "PROVIDER",
        "phoneNumber": "+966555444445",
        "amount": 910,
        "isSender": true
      }
    ],
    "isAcceptable": true
  }
}

GETGet Contract

Retrieve contract details and current status

Endpoint

GET /api/external/contracts/{contract_id}
Note:If the ID of a parent "complex" contract is specified, the info of that contract only (without milestones) will be returned. To get milestone details, use the milestone ID directly or use the "Get Contract Milestones" API.

Response (200 OK)

{
  "status": 200,
  "timestamp": "2026-01-25T11:19:00.872608",
  "data": {
    "id": "6971061074385b2c31672af3",
    "version": 1,
    "shortId": "UEVlKJpT",
    "type": "COMPLEX_CONTRACT",
    "senderId": "12345678",
    "senderPhoneNumber": null,
    "senderRole": "BROKER",
    "receiverId": null,
    "receiverPhoneNumber": null,
    "receiverRole": null,
    "provider": null,
    "customer": null,
    "itemDetail": {
      "title": "test contract",
      "description": "test description",
      "fields": null,
      "images": [
        "image url example"
      ],
      "attachments": []
    },
    "itemPrice": 0.0,
    "unitPrice": null,
    "quantity": null,
    "originalQuantity": 0,
    "fee": 0.0,
    "feePercentage": 0.0,
    "totalAmount": 0.0,
    "currency": null,
    "feePayee": "PROVIDER",
    "status": "CREATED",
    "createdAt": "2026-01-21T17:00:00.724+00:00",
    "updatedAt": "2026-01-21T17:12:02.769+00:00",
    "clientReferenceId": null,
    "contractClassification": "BASIC",
    "isParent": true,
    "parentId": null,
    "brokerFee": 0.0,
    "parties": [
      {
        "userId": "23456789",
        "role": "PROVIDER",
        "phoneNumber": "+966555444445",
        "sudoRole": null,
        "sudoName": null,
        "isSender": true,
        "amount": 910.0,
        "fee": 36.4,
        "feeType": null,
        "feePercentage": 0.04,
        "status": "JOINED",
        "arbitrator": false,
        "credited": false,
        "invitationId": null,
        "rejectionReason": null
      },
      {
        "userId": "12345678",
        "role": "BROKER",
        "phoneNumber": "+966559555555",
        "sudoRole": null,
        "sudoName": null,
        "isSender": true,
        "amount": 99100.0,
        "fee": 3964.0,
        "feeType": null,
        "feePercentage": 0.04,
        "status": "JOINED",
        "arbitrator": true,
        "credited": false,
        "invitationId": null,
        "rejectionReason": null
      }
    ],
    "partiesProfiles": {
      "PROVIDER": [
        {
          "id": 1234,
          "userIdentification": 23456789,
          "phoneNumber": "+966555444445",
          "nationalIdVerified": false,
          "profile": {
            "firstName": "test",
            "lastName": "user",
            "fullName": "test user"
          }
        }
      ],
      "BROKER": [
        {
          "id": 2345,
          "userIdentification": 12345678,
          "phoneNumber": "+966559555555",
          "nationalIdVerified": false,
          "profile": {
            "firstName": "test",
            "lastName": "user2",
            "fullName": "test user2"
          }
        }
      ]
    },
    "deadLine": null,
    "metaData": null,
    "category": "Services",
    "transactions": [],
    "addonFeesList": [],
    "shipment": {
      "number": null,
      "type": null,
      "shipmentCompany": null,
      "provider": null,
      "fee": 0.0,
      "currency": null,
      "feePayee": null,
      "info": null,
      "shipmentRequestId": null,
      "bookingId": null,
      "stickerUrl": null,
      "createdAt": "2026-01-21T16:59:57.809+00:00"
    },
    "returnShipment": null,
    "addressesMap": null,
    "acceptanceConditions": null,
    "cancellationConditions": null,
    "activeChildrenCount": 1,
    "activeChildrenTotalAmount": 100000.0,
    "activeChildrenPartiesCount": 3,
    "isInspectable": false,
    "isAcceptable": true,
    "paymentMethods": null,
    "currentStep": null,
    "operationsMetaData": null,
    "organization": {
      "organizationCode": "merchant_organization_code",
      "accountId": 2384
    },
    "originalItemPrice": null,
    "deliveryInDays": 5,
    "deliveryInMinutes": 0,
    "returnPolicy": null,
    "inspectionPeriod": 2,
    "returnFee": 0.0,
    "returnFeePayee": null,
    "returnItem": null,
    "waffyTermsAccepted": false,
    "escalations": [],
    "reminders": [],
    "customerAdditionalInfo": null,
    "customerShippingAddress": null,
    "organizationCode": "merchant_organization_code",
    "redemptionId": null,
    "isPrivate": null,
    "feePercentageMap": null,
    "address": null,
    "deliveryNotes": null,
    "cashOutAmountList": null,
    "waffyExtraFees": [],
    "cashOutAttachments": null,
    "cashOutComment": null,
    "settlementActorId": null,
    "settledAt": null,
    "cashOutParticipantAmountMap": null,
    "invoices": [],
    "settlementOut": false,
    "finalItemPrice": 0.0,
    "deservedFees": 0.0,
    "settled": false,
    "hasVoucher": false,
    "shippable": false
  }
}

GETGet Contract Milestones

Retrieve milestones for a parent contract with pagination

Endpoint

GET /api/external/contracts?parentId={parent_contract_id}&sort=createdAt%2CASC
Note:The contract ID is the parent "complex" contract that we need to query its milestones.

Response (200 OK)

{
  "status": 200,
  "timestamp": "2026-01-25T11:21:45.578018",
  "data": {
    "content": [
      {
        "id": "697107b674385b2c31672af5",
        "version": 4,
        "shortId": "pUZB9kCK",
        "type": "MILESTONE_CONTRACT",
        "senderId": "12345678",
        "senderRole": "BROKER",
        "receiverRole": "CUSTOMER",
        "itemDetail": {
          "title": "دفعة اوي",
          "description": "",
          "fields": null,
          "images": null,
          "attachments": null
        },
        "itemPrice": 100000.0,
        "fee": 4000.0,
        "feePercentage": 0.04,
        "totalAmount": 104000.0,
        "currency": "SAR",
        "feePayee": "PROVIDER",
        "status": "CREATED",
        "createdAt": "2026-01-21T17:07:02.545+00:00",
        "updatedAt": "2026-01-21T17:12:02.912+00:00",
        "contractClassification": "BASIC",
        "isParent": false,
        "parentId": "6971061074385b2c31672af3",
        "brokerFee": 0.0,
        "parties": [
          {
            "userId": "23456789",
            "role": "CUSTOMER",
            "phoneNumber": "+966555444444",
            "sudoRole": null,
            "sudoName": null,
            "isSender": false,
            "amount": 100000.0,
            "fee": 4000.0,
            "feeType": null,
            "feePercentage": 0.04,
            "status": "JOINED",
            "arbitrator": false,
            "credited": false,
            "invitationId": null,
            "rejectionReason": null
          },
          {
            "userId": "12345678",
            "role": "BROKER",
            "phoneNumber": "+966559555555",
            "sudoRole": null,
            "sudoName": null,
            "isSender": true,
            "amount": 99100.0,
            "fee": 3964.0,
            "feeType": null,
            "feePercentage": 0.04,
            "status": "JOINED",
            "arbitrator": true,
            "credited": false,
            "invitationId": null,
            "rejectionReason": null
          },
          {
            "userId": "34567891",
            "role": "PROVIDER",
            "phoneNumber": "+966555444445",
            "sudoRole": null,
            "sudoName": null,
            "isSender": true,
            "amount": 910.0,
            "fee": 36.4,
            "feeType": null,
            "feePercentage": 0.04,
            "status": "JOINED",
            "arbitrator": false,
            "credited": false,
            "invitationId": null,
            "rejectionReason": null
          }
        ],
        "partiesProfiles": {
          "CUSTOMER": [
            {
              "id": 2224,
              "userIdentification": 23456789,
              "phoneNumber": "+966555444444",
              "nationalIdVerified": false,
              "profile": {
                "firstName": "test",
                "lastName": "user",
                "fullName": "test user"
              }
            }
          ],
          "BROKER": [
            {
              "id": 2178,
              "userIdentification": 12345678,
              "phoneNumber": "+966559555555",
              "nationalIdVerified": false,
              "profile": {
                "firstName": "test",
                "lastName": "",
                "fullName": "test "
              }
            }
          ],
          "PROVIDER": [
            {
              "id": 2223,
              "userIdentification": 34567891,
              "phoneNumber": "+966555444445",
              "nationalIdVerified": false,
              "profile": {
                "firstName": "test",
                "lastName": "user",
                "fullName": "test user"
              }
            }
          ]
        },
        "deadLine": "2024-10-28T10:34:57.536+00:00",
        "metaData": null,
        "category": null,
        "transactions": [],
        "addonFeesList": [
          {
            "amount": 10.0,
            "feeType": "FLAT",
            "description": "Extra 10% Amount",
            "beneficiary": "+966559555555",
            "payee": "+966555444444",
            "type": "EXTRA_AMOUNT"
          }
        ],
        "shipment": {
          "number": null,
          "type": null,
          "shipmentCompany": null,
          "provider": null,
          "fee": 0.0,
          "currency": null,
          "feePayee": null,
          "info": null,
          "shipmentRequestId": null,
          "bookingId": null,
          "stickerUrl": null,
          "createdAt": "2026-01-21T17:07:00.657+00:00"
        },
        "returnShipment": null,
        "addressesMap": null,
        "acceptanceConditions": null,
        "cancellationConditions": null,
        "activeChildrenCount": null,
        "activeChildrenTotalAmount": null,
        "activeChildrenPartiesCount": null,
        "isInspectable": false,
        "isAcceptable": true,
        "paymentMethods": null,
        "currentStep": null,
        "operationsMetaData": null,
        "organization": {
          "organizationCode": "merchant_organization_code",
          "accountId": 2384
        },
        "originalItemPrice": null,
        "deliveryInDays": 5,
        "deliveryInMinutes": 0,
        "returnPolicy": null,
        "inspectionPeriod": 2,
        "returnFee": 0.0,
        "returnFeePayee": null,
        "returnItem": null,
        "waffyTermsAccepted": false,
        "escalations": [],
        "reminders": [],
        "customerAdditionalInfo": null,
        "customerShippingAddress": null,
        "organizationCode": "merchant_organization_code",
        "redemptionId": null,
        "isPrivate": null,
        "feePercentageMap": {
          "normalFee": 0.04,
          "tabbyFee": 0.055
        },
        "address": null,
        "deliveryNotes": null,
        "cashOutAmountList": null,
        "waffyExtraFees": [],
        "cashOutAttachments": null,
        "cashOutComment": null,
        "settlementActorId": null,
        "settledAt": null,
        "cashOutParticipantAmountMap": null,
        "invoices": [],
        "settlementOut": false,
        "finalItemPrice": 100000.0,
        "deservedFees": 4000.0,
        "settled": false,
        "hasVoucher": false,
        "shippable": false
      }
    ],
    "pageable": {
      "sort": {
        "empty": false,
        "sorted": true,
        "unsorted": false
      },
      "offset": 0,
      "pageNumber": 0,
      "pageSize": 10,
      "paged": true,
      "unpaged": false
    },
    "totalElements": 1,
    "totalPages": 1,
    "last": true,
    "sort": {
      "empty": false,
      "sorted": true,
      "unsorted": false
    },
    "size": 10,
    "number": 0,
    "numberOfElements": 1,
    "first": true,
    "empty": false
  }
}

GETList Contracts

Retrieve a page of contracts, with filters. Needs a client admin token.

Endpoint

GET /api/external/contracts

Query Parameters

ParameterTypeDescription
pageintegerPage number, starting at 0.
sizeintegerPage size. Default 10.
sortstringField and direction, for example createdAt,ASC. Default: newest first.
statusstringOne or more contract statuses, for example CREATED or PAID.
participantIdstringContracts the user takes part in.
senderIdstringContracts sent by this user.
receiverIdstringContracts received by this user.
parentIdstringThe milestones of a parent ("complex") contract.
searchKeyWordstringFree-text search.
createdAtFrom, createdAtTostringCreation date range, format yyyy-MM-dd HH:mm.

These are the most used filters. The interactive reference lists the rest.

Contract Statuses

The status field of a contract

A contract's status is one of the ContractStatus values, for example CREATED, PAID, COMPLETED, CANCELED or RESOLVED_REFUND_CUSTOMER. There are many more, because a milestone contract passes through payment, delivery, inspection, dispute and settlement states.

Errors

An error uses the same envelope as a success: status, timestamp and an error object with status and message. Depending on the error it may also carry reason, errorCode, subErrors or validationErrors.

404 Not Found

{
  "status": 404,
  "timestamp": "2026-01-20T18:52:22.831103",
  "error": {
    "status": "NOT_FOUND",
    "message": "Contract was not found for parameters {id=6971061074385b2c31672af3}"
  }
}

More examples and the list of causes are in the error guide.

Build a payment

The whole flow, step by step, from the first token to settlement

Webhooks Integration

Get real-time notifications for contract events