CreateDispute
Step 1: Create dispute
User can create dispute for a contract by providing the requester's id, contract id and reason for dispute.
Implementation Examples
POST {{BaseUrl}}/apps/api/disputes
Headers:
- Authorization:
Bearer {access_token}— Replace{access_token}with the token obtained from Step 1. - Content-Type: application/json
{
"requesterPlatformRefId": "USR_01KZ15DDR0KN",
"externalContractId": "CNT-000000GFZ000",
"reason": "OtherDisputeReason",
"otherMessage": "some text to explain the dispute",
"suggestions": "explain the suggestions",
"attachmentsIds": ["ATT-000000GFZ000", "ATT-000000GFZ001"]
}
Field Descriptions
| Field Name | Type | Description | Required / Notes / Example |
|---|---|---|---|
| requesterPlatformRefId | string | Requester's platform reference ID | Required |
| externalContractId | string | External contract ID | Required |
| reason | string | Reason for dispute | Required |
| otherMessage | string | Additional message for dispute | Optional |
| suggestions | string | Suggestions for dispute resolution | Optional |
| attachmentsIds | array | List of attachments Ids to proof user's claim | Required |
Example Request (cURL)
curl --location '{{BaseUrl}}/apps/api/dispute' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YourTokenGoesHere' \
--data '{
"externalContractId": "CNT-01KX12PR976YD7FFKRWNQ58DQT",
"reason": "ProductNotGood",
"suggestions": "Suggestions",
"attachmentsIds": ["ATT-000000GFZ000"],
}'
Example Response
{
"data": {
"disputeId": 1
},
"message": "Dispute created and contract status updated successfully.",
"status": 200,
"errorCode": null,
"validationErrors": []
}
Reasons options
public enum DisputeReasons
{
ProductNotGood = 1,
ServiceNotMatchingRequirements = 2,
DeliveryIssue = 3,
PaymentIssue = 4,
ContractViolation = 5,
DamagedProduct = 6,
ServiceIncomplete = 7,
OtherDisputeReason = 99
}
Webhooks sent when a dispute is created
Creating a dispute sends two webhooks: dispute.created, and a status webhook. The status webhook is milestone.disputed when the contract has milestones, and contract.disputed when it does not.
raisedBy is ThirdParty when the dispute is opened through this API. disputeId is sent as a string.
dispute.created does not include status, previousStatus, or amount. When the dispute is on a milestone, it includes milestoneId.
Contract with milestones
dispute.created
{
"id": "aa3490f8-6862-404d-8841-f391f4484aa7",
"event": "dispute.created",
"createdAt": "2026-10-06T10:47:41.6640885Z",
"data": {
"contractId": "CNT-01M48D4SZYAW",
"milestoneId": "MST-01M48D4SZHR5",
"disputeId": "774",
"raisedBy": "ThirdParty",
"currency": "SAR",
"timestamp": "2026-10-06T10:47:41.6619642Z"
}
}
milestone.disputed
The milestone status stays Escrow. The contract moves to Dispute in contractStatus.
{
"id": "25e9385e-58fd-431f-a77d-b67ecf2d900c",
"event": "milestone.disputed",
"createdAt": "2026-10-06T10:47:41.6573599Z",
"data": {
"contractId": "CNT-01M48D4SZYAW",
"milestoneId": "MST-01M48D4SZHR5",
"disputeId": "774",
"raisedBy": "ThirdParty",
"status": "Escrow",
"previousStatus": "Pending",
"contractStatus": "Dispute",
"contractPreviousStatus": "Approved",
"amount": 1000,
"currency": "SAR",
"timestamp": "2026-10-06T10:47:41.6542281Z"
}
}
Contract without milestones
dispute.created omits milestoneId.
{
"id": "342399b5-0f59-4aa7-92a8-efb098cfad12",
"event": "dispute.created",
"createdAt": "2026-10-06T11:32:48.230923Z",
"data": {
"contractId": "CNT-01M48FPS2A4R",
"disputeId": "777",
"raisedBy": "ThirdParty",
"currency": "SAR",
"timestamp": "2026-10-06T11:32:48.2285619Z"
}
}
contract.disputed
status is the contract status. It moves from Escrow to Dispute.
{
"id": "d96b3729-5d4b-446e-9521-b32e3d8813be",
"event": "contract.disputed",
"createdAt": "2026-10-06T11:32:48.2263733Z",
"data": {
"contractId": "CNT-01M48FPS2A4R",
"disputeId": "777",
"raisedBy": "ThirdParty",
"status": "Dispute",
"previousStatus": "Escrow",
"amount": 3000.00,
"currency": "SAR",
"timestamp": "2026-10-06T11:32:48.2241167Z"
}
}