Skip to main content

Step 2: Create a Contract

After obtaining the access token, use it to create a payment contract.

Endpoint​

POST {{BaseUrl}}/apps/api/contracts

Headers

  • Authorization: Bearer {access_token}
    Replace {access_token} with the token obtained from login (Step 1).

  • Content-Type: application/json

Request Body​

{
"title": "Sell a property",
"contractServiceType": "product",
"BuyerParty": {
"userRefId" : "USR_abc001",
"phoneNumber": "966583944460",
"firstName": "Kareem",
"lastName": "Hasan",
"identity": "1071855555"
},
"SellerParty": {
"userRefId" : "USR_abc002",
"phoneNumber": "966583944461",
"firstName": "Ashraf",
"lastName": "Ali",
"identity": "1071866666"
},
"amount": 1000,
"description": "External Iphone mobile",
"notes": "notes for mobile",
"reference": "12321",
"buyerFeePercentage": 5,
"sellerFeePercentage": 3,
"metaData": {
"metadata1": "1",
"metadata2": "2",
"metadata3": "",
"metadata4": ""
},
"callbackUrl": "https://yourdomain.com/usercart",
"Milestones": [
{
"Name": "milestone 1 name",
"Description": "milestone 1 description",
"Amount": 600,
"DueDate": "2026-12-20T10:00:00.000Z"
},
{
"Name": "milestone 2 name",
"Description": "milestone 2 description",
"Amount": 400,
"DueDate": "2026-12-31T09:35:30.369Z"
}
]
}

Field Descriptions​

Field NameTypeDescriptionRequired / Notes / Example
titlestringContract titleRequired
Example: "Sell an iPhone"
contractServiceTypestringType of service for the contractRequired
Expected Values: "Product", "Service"
BuyerPartyobject (Party)Buyer informationRequired
SellerPartyobject (Party)Seller informationRequired
amountnumberContract amountRequired
Example: 1000
descriptionstringContract descriptionOptional
Example: "External iPhone mobile"
notesstringAdditional notesOptional
Example: "notes for mobile"
referencestringExternal reference identifierOptional
Example: "12321"
metaDataobject (MetaData)Custom key-value metadataOptional
callbackUrlstringCallback URL for contract eventsOptional
Example: "https://yourdomain.com/usercart"
Milestoneslist of objects (Milestone)Separate contract into multiple milestonesOptional
buyerFeePercentagenumberYour fee charged to the buyer at checkoutOptional
Range: 0–100
Requires contract-level fee
Learn more
sellerFeePercentagenumberYour fee deducted from the seller at releaseOptional
Range: 0–100
Requires contract-level fee
Learn more
noFeesAppliedbooleanWaives your platform fee on this contract. Your agreement with WePay applies as usualOptional
Default: false
Requires contract-level fee
Learn more

Contract Fees​

By default, the fee agreed with WePay for your account applies to every contract you create; it is charged to the buyer.

If contract-level fee is enabled for your account, you can set the fee on each contract using buyerFeePercentage, sellerFeePercentage or noFeesApplied. In contract-level mode, every contract must include a fee field; otherwise the request returns 400 BuyerOrSellerFeeRequired.

Note: Sending any of these fields while contract-level fee is not enabled returns 403 with error code 1887.

See Contract Fees for the full guide, worked examples, and validation rules.

Party (BuyerParty / SellerParty)

Field NameTypeDescriptionRequired / Notes / Example
userRefId*stringUser identifier in wepay systemOptional
phoneNumberstringParty phone number (including country code)Required if userRefId is not provided
Example: "966583944460"
firstName**stringFirst nameRequired if userRefId is not provided
Example: "Kareem"
lastName**stringLast nameRequired if userRefId is not provided
Example: "Hasan"
identity**stringIdentity numberOptional, even if userRefId is not provided
Example: "1071855555"

*userRefId is optional in the request. It is a unique identifier across all parties in WePay system.

**firstName, lastName, and identity are sent to pre-fill the KYC form Personal info.

To get userRefId, you can call the User Onboarding API to retrieve a user and obtain his userRefId, if exists.

You can also choose to not provide userRefId in the request, or just provide the party's phone number and name and WePay will try to find an existing user with the same phone number. If the user is a new one, it will be created automatically in the system and a new userRefId will be generated for him, and will be returned in the response. You can then store this userRefId in your system for future reference.

If you want to create a user in Wepay and get the userRefId before creating a contract, you can use the User Creation API to create a new user and get his userRefId, then use this userRefId in the contract creation request.

Note: On contract creation, the seller receives an SMS with a KYC link to verify his identity.

MetaData

Field NameTypeDescriptionRequired / Notes / Example
metadata1stringCustom metadata fieldOptionalExample: "1"
metadata2stringCustom metadata fieldOptionalExample: "2"
metadata3stringCustom metadata fieldOptionalExample: ""
metadata4stringCustom metadata fieldOptionalExample: ""

Milestone

Field NameTypeDescriptionRequired / Notes / Example
NamestringMilestone nameRequired Example: "milestone 1 name"
DescriptionstringMilestone DescriptionOptional Example: "milestone 1 description"
AmountNumberMilestone amountRequired Example: 600
Note: Must be lower than contract amount and the total of all milestones amounts must be equal to the contract amount
DueDatestring (date-time)Milestone due date (UTC)Required
Example: 2026-12-20T10:00:000Z

Response:​

Result<ExternalCreateContractResponse>

Field NameTypeDescriptionRequired / Notes / Example
statusintIndicates whether the request was successfulRequired
Example: 200
messagestringResult messageOptional
Example: "Contract created successfully"
validationErrorsarray of stringList of validation or business errorsOptional
dataobject (ExternalCreateContractResponse)Contract creation result dataOptional

ExternalCreateContractResponse

Field NameTypeDescriptionRequired / Notes / Example
contractIdstringUnique external contract identifierRequired

Example: "CNT-2601-00100003"
statusstring (ContractStatus)Current contract statusRequired

Example: "pending"
contractServiceTypestring (ContractServiceType)Type of contract serviceRequired

Example: "product"
checkoutUrlstringCheckout URL for completing paymentRequired

Example: "/checkout?token=encodedToken"
The token is valid for 10 minutes. If expired, you need to request a new one by calling /apps/api/contracts/checkout
buyerPartyobject (ExternalContractParty)Buyer party detailsRequired
sellerPartyobject (ExternalContractParty)Seller party detailsRequired
referencestringExternal reference identifierOptional Nullable
metaDataobject (ContractMetaData)Custom metadataOptional Nullable
milestonesarray of MilestoneContract milestonesRequired
pricingLineItemsarray of ExternalPriceLineItemPricing breakdown itemsRequired
createdDatestring (date-time)Contract creation timestamp (UTC)Required

Example: 2024-01-15T10:30:00Z

ExternalContractParty

Field NameTypeDescriptionRequired / Notes / Example
userRefIdstringUser identifier in wepayRequired
firstNamestringFirst nameRequired
Example: "Kareem"
lastNamestringLast nameRequired
Example: "Hasan"
phoneNumberstringPhone number including country codeRequired
Example: "966583944460"

ContractMetaData

Field NameTypeDescriptionRequired / Notes / Example
metadata1stringCustom metadata fieldOptional
metadata2stringCustom metadata fieldOptional
metadata3stringCustom metadata fieldOptional
metadata4stringCustom metadata fieldOptional

Milestone

Field NameTypeDescriptionRequired / Notes / Example
IdnumberMilestone identifierRequired
Example: 13
namestringMilestone nameRequired

Example: "Delivery"
descriptionstringMilestone descriptionOptional
amountnumberMilestone amountRequired

Example: 500
dueDatestring (date-time)Milestone due date (UTC)Required

Example: 2024-02-01T00:00:00Z
pricingLineItemsarray of ExternalPriceLineItemPricing breakdown itemsRequired

Milestone Validation Rules​

RuleRequirement
Total amountsMust equal contract amount
Milestone amountMust be > 0
DueDate formatISO 8601 UTC (with Z suffix)
NameRequired field
DescriptionOptional field

Important: Milestone Amount Calculation​

Request Amount = Base contract amount
Response Amount = Base + all fees + taxes

Example:

  • Request: 600 SAR (base)
  • Response: 669.00 SAR (contract amount plus the fees and VAT paid by the buyer)

See pricingLineItems array for full breakdown.

ExternalPriceLineItem

Field NameTypeDescriptionRequired / Notes / Example
lineTypestring (PricingLineType)Pricing line typeRequired

Example: "EscrowFee"
LineTypeDescriptionstringPricing line type descriptionRequired
rolestring (PricingRole)Party responsible for the amountRequired

Example: "Buyer"
RoleDescriptionstringRole descriptionRequired
amountnumberAmount valueRequired

Example: 50
descriptionstringPricing line descriptionOptional
orderintegerDisplay orderRequired

Example: 1

Example Request (cURL)​

curl -X POST "{{BaseUrl}}/apps/api/contracts" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "TEST Sell a property",
"contractServiceType": "Product",
"BuyerParty": {
"phoneNumber": "966583944460",
"firstName": "Kareem",
"lastName": "Hasan"
},
"SellerParty": {
"phoneNumber": "966583944461",
"firstName": "Ashraf",
"lastName": "Ali"
},
"amount": 1000,
"description": "TEST External Iphone mobile",
"notes": "notes for mobile",
"callbackUrl": "http://localhost:3000/en/payment-success",
"Milestones": [
{
"Name": "milestone 1 name",
"Description": "milestone 1 description",
"Amount": 600,
"DueDate": "2026-12-20T10:00:00.000Z"
},
{
"Name": "milestone 2 name",
"Description": "milestone 2 description",
"Amount": 400,
"DueDate": "2026-12-31T09:35:30.369Z"
}
]
}'

Note: API uses camelCase for JSON responses:

  • Request: "Milestones" (PascalCase - C# convention)
  • Response: "milestones" (camelCase - JSON convention)

DueDate Format: Always use UTC timezone

  • Example: "2026-12-20T10:00:00.000Z"
  • System converts to Saudi time (UTC+3) for display

Note: Milestones are read-only after contract creation.

Example Response​

{
"data": {
"contractId": "CNT-2601-00100003",
"status": "pending",
"contractServiceType": "product",
"checkoutUrl": "{{BaseUrl}}/checkout?token=RSGFF38PXVO....",
"buyerParty": {
"userRefId": "USR_20260405152053_5487",
"firstName": "Kareem",
"lastName": "Hasan",
"phoneNumber": "966583944460"
},
"sellerParty": {
"userRefId": "USR_20260405151029_7034",
"firstName": "Ashraf",
"lastName": "Ali",
"phoneNumber": "966583944461"
},
"reference": "12321",
"metaData": {
"metadata1": "1",
"metadata2": "2",
"metadata3": "",
"metadata4": ""
},
"milestones": [
{
"id": 12,
"name": "milestone 1 name",
"description": "milestone 1 description",
"dueDate": "2026-12-20T10:00:00.000Z",
"amount": 669.00,
"pricingLineItems": [
{
"lineType": "contractAmount",
"role": "buyer",
"amount": 600,
"description": null,
"order": 1
},
{
"lineType": "escrowFee",
"role": "thirdParty",
"amount": 15.0,
"description": null,
"order": 2
},
{
"lineType": "escrowFeeTax",
"role": "thirdParty",
"amount": 2.25,
"description": null,
"order": 3
},
{
"lineType": "externalPlatformFee",
"role": "buyer",
"amount": 60.00,
"description": null,
"order": 4
},
{
"lineType": "externalPlatformFeeTax",
"role": "buyer",
"amount": 9.00,
"description": null,
"order": 5
},
{
"lineType": "netEscrowAmountToSeller",
"role": "seller",
"amount": 600,
"description": null,
"order": 6
}
]
},
{
"id": 13,
"name": "milestone 2 name",
"description": "milestone 2 description",
"dueDate": "2026-12-31T09:35:30.369Z",
"amount": 457.5,
"pricingLineItems": [
{
"lineType": "contractAmount",
"role": "buyer",
"amount": 400,
"description": null,
"order": 1
},
{
"lineType": "escrowFee",
"role": "thirdParty",
"amount": 10.00,
"description": null,
"order": 2
},
{
"lineType": "escrowFeeTax",
"role": "thirdParty",
"amount": 1.50,
"description": null,
"order": 3
},
{
"lineType": "externalPlatformFee",
"role": "buyer",
"amount": 40.00,
"description": null,
"order": 4
},
{
"lineType": "externalPlatformFeeTax",
"role": "buyer",
"amount": 6.00,
"description": null,
"order": 5
},
{
"lineType": "netEscrowAmountToSeller",
"role": "seller",
"amount": 400,
"description": null,
"order": 6
}
]
}
],
"pricingLineItems": [
{
"lineType": "contractAmount",
"role": "buyer",
"amount": 1000,
"description": null,
"order": 1
},
{
"lineType": "escrowFee",
"role": "thirdParty",
"amount": 25.0,
"description": null,
"order": 2
},
{
"lineType": "escrowFeeTax",
"role": "thirdParty",
"amount": 3.75,
"description": null,
"order": 3
},
{
"lineType": "externalPlatformFee",
"role": "buyer",
"amount": 100.0,
"description": null,
"order": 4
},
{
"lineType": "externalPlatformFeeTax",
"role": "buyer",
"amount": 15.0,
"description": null,
"order": 5
},
{
"lineType": "netEscrowAmountToSeller",
"role": "seller",
"amount": 1000,
"description": null,
"order": 6
}
],
"createdDate": "2026-01-25T10:28:10.4874015Z"
},
"message": "Contract created successfully.",
"status": 200,
"validationErrors": []
}

Example Response with Buyer and Seller Fees​

When contract-level fee is enabled and you charge both parties, the pricing contains two externalPlatformFee lines — one for each party — each followed by its own tax line.

Request:

{
"title": "Sell a property",
"contractServiceType": "product",
"amount": 1000,
"buyerFeePercentage": 5,
"sellerFeePercentage": 3,
"BuyerParty": { "phoneNumber": "966583944460", "firstName": "Kareem", "lastName": "Hasan" },
"SellerParty": { "phoneNumber": "966583944461", "firstName": "Ashraf", "lastName": "Ali" }
}

Resulting pricingLineItems:

"pricingLineItems": [
{
"lineType": "contractAmount",
"role": "buyer",
"amount": 1000,
"order": 1
},
{
"lineType": "externalPlatformFee",
"role": "buyer",
"amount": 50.00,
"order": 4
},
{
"lineType": "externalPlatformFeeTax",
"role": "buyer",
"amount": 7.50,
"order": 5
},
{
"lineType": "externalPlatformFee",
"role": "seller",
"amount": 30.00,
"order": 6
},
{
"lineType": "externalPlatformFeeTax",
"role": "seller",
"amount": 4.50,
"order": 7
},
{
"lineType": "netEscrowAmountToSeller",
"role": "seller",
"amount": 965.50,
"order": 8
}
]

The buyer pays 1,057.50 at checkout. The seller receives 965.50 when the contract is released, because the seller fee is deducted at release rather than at payment.

Party name and identity sent at creation pre-fill the KYC form.

See Contract Fees for the complete guide.