curl --request PUT \
--url https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'customer-id: <customer-id>' \
--data '
{
"amount": 1200000,
"purpose": "Company website build (revised scope)",
"description": "3-phase delivery (updated budget)",
"whoPays": "buyer",
"maxDelivery": 45,
"deliveryTimeline": "days",
"totalQuantity": 1,
"categoryId": "665f1b2c9a1e4d0012ab3c30",
"milestones": [
{
"title": "Design",
"description": "Figma mockups",
"amount": 400000,
"dueDate": "2026-07-20",
"customerId": "665f1b2c9a1e4d0012ab3c40"
},
{
"title": "Development",
"description": "Frontend + backend",
"amount": 600000,
"dueDate": "2026-08-20"
},
{
"title": "Deployment",
"description": "Go-live + handover",
"amount": 200000
}
]
}
'import requests
url = "https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken}"
payload = {
"amount": 1200000,
"purpose": "Company website build (revised scope)",
"description": "3-phase delivery (updated budget)",
"whoPays": "buyer",
"maxDelivery": 45,
"deliveryTimeline": "days",
"totalQuantity": 1,
"categoryId": "665f1b2c9a1e4d0012ab3c30",
"milestones": [
{
"title": "Design",
"description": "Figma mockups",
"amount": 400000,
"dueDate": "2026-07-20",
"customerId": "665f1b2c9a1e4d0012ab3c40"
},
{
"title": "Development",
"description": "Frontend + backend",
"amount": 600000,
"dueDate": "2026-08-20"
},
{
"title": "Deployment",
"description": "Go-live + handover",
"amount": 200000
}
]
}
headers = {
"customer-id": "<customer-id>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {
'customer-id': '<customer-id>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: 1200000,
purpose: 'Company website build (revised scope)',
description: '3-phase delivery (updated budget)',
whoPays: 'buyer',
maxDelivery: 45,
deliveryTimeline: 'days',
totalQuantity: 1,
categoryId: '665f1b2c9a1e4d0012ab3c30',
milestones: [
{
title: 'Design',
description: 'Figma mockups',
amount: 400000,
dueDate: '2026-07-20',
customerId: '665f1b2c9a1e4d0012ab3c40'
},
{
title: 'Development',
description: 'Frontend + backend',
amount: 600000,
dueDate: '2026-08-20'
},
{title: 'Deployment', description: 'Go-live + handover', amount: 200000}
]
})
};
fetch('https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'amount' => 1200000,
'purpose' => 'Company website build (revised scope)',
'description' => '3-phase delivery (updated budget)',
'whoPays' => 'buyer',
'maxDelivery' => 45,
'deliveryTimeline' => 'days',
'totalQuantity' => 1,
'categoryId' => '665f1b2c9a1e4d0012ab3c30',
'milestones' => [
[
'title' => 'Design',
'description' => 'Figma mockups',
'amount' => 400000,
'dueDate' => '2026-07-20',
'customerId' => '665f1b2c9a1e4d0012ab3c40'
],
[
'title' => 'Development',
'description' => 'Frontend + backend',
'amount' => 600000,
'dueDate' => '2026-08-20'
],
[
'title' => 'Deployment',
'description' => 'Go-live + handover',
'amount' => 200000
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"customer-id: <customer-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken}"
payload := strings.NewReader("{\n \"amount\": 1200000,\n \"purpose\": \"Company website build (revised scope)\",\n \"description\": \"3-phase delivery (updated budget)\",\n \"whoPays\": \"buyer\",\n \"maxDelivery\": 45,\n \"deliveryTimeline\": \"days\",\n \"totalQuantity\": 1,\n \"categoryId\": \"665f1b2c9a1e4d0012ab3c30\",\n \"milestones\": [\n {\n \"title\": \"Design\",\n \"description\": \"Figma mockups\",\n \"amount\": 400000,\n \"dueDate\": \"2026-07-20\",\n \"customerId\": \"665f1b2c9a1e4d0012ab3c40\"\n },\n {\n \"title\": \"Development\",\n \"description\": \"Frontend + backend\",\n \"amount\": 600000,\n \"dueDate\": \"2026-08-20\"\n },\n {\n \"title\": \"Deployment\",\n \"description\": \"Go-live + handover\",\n \"amount\": 200000\n }\n ]\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("customer-id", "<customer-id>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken}")
.header("customer-id", "<customer-id>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": 1200000,\n \"purpose\": \"Company website build (revised scope)\",\n \"description\": \"3-phase delivery (updated budget)\",\n \"whoPays\": \"buyer\",\n \"maxDelivery\": 45,\n \"deliveryTimeline\": \"days\",\n \"totalQuantity\": 1,\n \"categoryId\": \"665f1b2c9a1e4d0012ab3c30\",\n \"milestones\": [\n {\n \"title\": \"Design\",\n \"description\": \"Figma mockups\",\n \"amount\": 400000,\n \"dueDate\": \"2026-07-20\",\n \"customerId\": \"665f1b2c9a1e4d0012ab3c40\"\n },\n {\n \"title\": \"Development\",\n \"description\": \"Frontend + backend\",\n \"amount\": 600000,\n \"dueDate\": \"2026-08-20\"\n },\n {\n \"title\": \"Deployment\",\n \"description\": \"Go-live + handover\",\n \"amount\": 200000\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["customer-id"] = '<customer-id>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"amount\": 1200000,\n \"purpose\": \"Company website build (revised scope)\",\n \"description\": \"3-phase delivery (updated budget)\",\n \"whoPays\": \"buyer\",\n \"maxDelivery\": 45,\n \"deliveryTimeline\": \"days\",\n \"totalQuantity\": 1,\n \"categoryId\": \"665f1b2c9a1e4d0012ab3c30\",\n \"milestones\": [\n {\n \"title\": \"Design\",\n \"description\": \"Figma mockups\",\n \"amount\": 400000,\n \"dueDate\": \"2026-07-20\",\n \"customerId\": \"665f1b2c9a1e4d0012ab3c40\"\n },\n {\n \"title\": \"Development\",\n \"description\": \"Frontend + backend\",\n \"amount\": 600000,\n \"dueDate\": \"2026-08-20\"\n },\n {\n \"title\": \"Deployment\",\n \"description\": \"Go-live + handover\",\n \"amount\": 200000\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"status": 200,
"message": "Milestone escrow updated successfully",
"data": {
"id": "665f1b2c9a1e4d0012ab3c10",
"amount": 1200000,
"purpose": "Company website build (revised scope)",
"whoPays": "buyer",
"fee": 30000,
"paymentToken": "PY_8AB12C9D3045",
"status": "PENDING",
"state": "AWAITING_PAYMENT",
"settlementType": "MILESTONE",
"milestones": [
{
"id": "665f1b2c9a1e4d0012ab3c24",
"title": "Design",
"description": "Figma mockups",
"amount": 400000,
"dueDate": "2026-07-20",
"status": "PENDING",
"releasedAt": null
},
{
"id": "665f1b2c9a1e4d0012ab3c25",
"title": "Development",
"description": "Frontend + backend",
"amount": 600000,
"dueDate": "2026-08-20",
"status": "PENDING",
"releasedAt": null
},
{
"id": "665f1b2c9a1e4d0012ab3c26",
"title": "Deployment",
"description": "Go-live + handover",
"amount": 200000,
"dueDate": null,
"status": "PENDING",
"releasedAt": null
}
],
"updatedAt": "2026-06-23T09:30:00.000Z"
}
}Edit milestone escrow
Replaces the details and the full milestone set of a milestone escrow (JSON body, no file upload). Editable only while the escrow is still AWAITING_PAYMENT, and only by the seller that created it. The same rules as creation apply: at least 2 milestones, every milestone amount is naira with at most two decimal places (minimum 1), and the sum of milestone amounts must equal amount. The platform fee is recalculated from the new amount and the milestone ids are regenerated. Requires the customer-id header (the seller). maxDelivery (1 to 365) and deliveryTimeline are required.
curl --request PUT \
--url https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'customer-id: <customer-id>' \
--data '
{
"amount": 1200000,
"purpose": "Company website build (revised scope)",
"description": "3-phase delivery (updated budget)",
"whoPays": "buyer",
"maxDelivery": 45,
"deliveryTimeline": "days",
"totalQuantity": 1,
"categoryId": "665f1b2c9a1e4d0012ab3c30",
"milestones": [
{
"title": "Design",
"description": "Figma mockups",
"amount": 400000,
"dueDate": "2026-07-20",
"customerId": "665f1b2c9a1e4d0012ab3c40"
},
{
"title": "Development",
"description": "Frontend + backend",
"amount": 600000,
"dueDate": "2026-08-20"
},
{
"title": "Deployment",
"description": "Go-live + handover",
"amount": 200000
}
]
}
'import requests
url = "https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken}"
payload = {
"amount": 1200000,
"purpose": "Company website build (revised scope)",
"description": "3-phase delivery (updated budget)",
"whoPays": "buyer",
"maxDelivery": 45,
"deliveryTimeline": "days",
"totalQuantity": 1,
"categoryId": "665f1b2c9a1e4d0012ab3c30",
"milestones": [
{
"title": "Design",
"description": "Figma mockups",
"amount": 400000,
"dueDate": "2026-07-20",
"customerId": "665f1b2c9a1e4d0012ab3c40"
},
{
"title": "Development",
"description": "Frontend + backend",
"amount": 600000,
"dueDate": "2026-08-20"
},
{
"title": "Deployment",
"description": "Go-live + handover",
"amount": 200000
}
]
}
headers = {
"customer-id": "<customer-id>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {
'customer-id': '<customer-id>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: 1200000,
purpose: 'Company website build (revised scope)',
description: '3-phase delivery (updated budget)',
whoPays: 'buyer',
maxDelivery: 45,
deliveryTimeline: 'days',
totalQuantity: 1,
categoryId: '665f1b2c9a1e4d0012ab3c30',
milestones: [
{
title: 'Design',
description: 'Figma mockups',
amount: 400000,
dueDate: '2026-07-20',
customerId: '665f1b2c9a1e4d0012ab3c40'
},
{
title: 'Development',
description: 'Frontend + backend',
amount: 600000,
dueDate: '2026-08-20'
},
{title: 'Deployment', description: 'Go-live + handover', amount: 200000}
]
})
};
fetch('https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'amount' => 1200000,
'purpose' => 'Company website build (revised scope)',
'description' => '3-phase delivery (updated budget)',
'whoPays' => 'buyer',
'maxDelivery' => 45,
'deliveryTimeline' => 'days',
'totalQuantity' => 1,
'categoryId' => '665f1b2c9a1e4d0012ab3c30',
'milestones' => [
[
'title' => 'Design',
'description' => 'Figma mockups',
'amount' => 400000,
'dueDate' => '2026-07-20',
'customerId' => '665f1b2c9a1e4d0012ab3c40'
],
[
'title' => 'Development',
'description' => 'Frontend + backend',
'amount' => 600000,
'dueDate' => '2026-08-20'
],
[
'title' => 'Deployment',
'description' => 'Go-live + handover',
'amount' => 200000
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"customer-id: <customer-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken}"
payload := strings.NewReader("{\n \"amount\": 1200000,\n \"purpose\": \"Company website build (revised scope)\",\n \"description\": \"3-phase delivery (updated budget)\",\n \"whoPays\": \"buyer\",\n \"maxDelivery\": 45,\n \"deliveryTimeline\": \"days\",\n \"totalQuantity\": 1,\n \"categoryId\": \"665f1b2c9a1e4d0012ab3c30\",\n \"milestones\": [\n {\n \"title\": \"Design\",\n \"description\": \"Figma mockups\",\n \"amount\": 400000,\n \"dueDate\": \"2026-07-20\",\n \"customerId\": \"665f1b2c9a1e4d0012ab3c40\"\n },\n {\n \"title\": \"Development\",\n \"description\": \"Frontend + backend\",\n \"amount\": 600000,\n \"dueDate\": \"2026-08-20\"\n },\n {\n \"title\": \"Deployment\",\n \"description\": \"Go-live + handover\",\n \"amount\": 200000\n }\n ]\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("customer-id", "<customer-id>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken}")
.header("customer-id", "<customer-id>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": 1200000,\n \"purpose\": \"Company website build (revised scope)\",\n \"description\": \"3-phase delivery (updated budget)\",\n \"whoPays\": \"buyer\",\n \"maxDelivery\": 45,\n \"deliveryTimeline\": \"days\",\n \"totalQuantity\": 1,\n \"categoryId\": \"665f1b2c9a1e4d0012ab3c30\",\n \"milestones\": [\n {\n \"title\": \"Design\",\n \"description\": \"Figma mockups\",\n \"amount\": 400000,\n \"dueDate\": \"2026-07-20\",\n \"customerId\": \"665f1b2c9a1e4d0012ab3c40\"\n },\n {\n \"title\": \"Development\",\n \"description\": \"Frontend + backend\",\n \"amount\": 600000,\n \"dueDate\": \"2026-08-20\"\n },\n {\n \"title\": \"Deployment\",\n \"description\": \"Go-live + handover\",\n \"amount\": 200000\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://staging.api.payluk.ng/v1/escrow/milestone/edit/{paymentToken}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["customer-id"] = '<customer-id>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"amount\": 1200000,\n \"purpose\": \"Company website build (revised scope)\",\n \"description\": \"3-phase delivery (updated budget)\",\n \"whoPays\": \"buyer\",\n \"maxDelivery\": 45,\n \"deliveryTimeline\": \"days\",\n \"totalQuantity\": 1,\n \"categoryId\": \"665f1b2c9a1e4d0012ab3c30\",\n \"milestones\": [\n {\n \"title\": \"Design\",\n \"description\": \"Figma mockups\",\n \"amount\": 400000,\n \"dueDate\": \"2026-07-20\",\n \"customerId\": \"665f1b2c9a1e4d0012ab3c40\"\n },\n {\n \"title\": \"Development\",\n \"description\": \"Frontend + backend\",\n \"amount\": 600000,\n \"dueDate\": \"2026-08-20\"\n },\n {\n \"title\": \"Deployment\",\n \"description\": \"Go-live + handover\",\n \"amount\": 200000\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"status": 200,
"message": "Milestone escrow updated successfully",
"data": {
"id": "665f1b2c9a1e4d0012ab3c10",
"amount": 1200000,
"purpose": "Company website build (revised scope)",
"whoPays": "buyer",
"fee": 30000,
"paymentToken": "PY_8AB12C9D3045",
"status": "PENDING",
"state": "AWAITING_PAYMENT",
"settlementType": "MILESTONE",
"milestones": [
{
"id": "665f1b2c9a1e4d0012ab3c24",
"title": "Design",
"description": "Figma mockups",
"amount": 400000,
"dueDate": "2026-07-20",
"status": "PENDING",
"releasedAt": null
},
{
"id": "665f1b2c9a1e4d0012ab3c25",
"title": "Development",
"description": "Frontend + backend",
"amount": 600000,
"dueDate": "2026-08-20",
"status": "PENDING",
"releasedAt": null
},
{
"id": "665f1b2c9a1e4d0012ab3c26",
"title": "Deployment",
"description": "Go-live + handover",
"amount": 200000,
"dueDate": null,
"status": "PENDING",
"releasedAt": null
}
],
"updatedAt": "2026-06-23T09:30:00.000Z"
}
}Authorizations
Your secret key as a Bearer token. The key prefix selects the environment: sk_test_... (staging) or sk_live_... (production); a key on the wrong host is refused with 403 Unauthorized Access. Each key is limited to 10 requests per minute (429 beyond that) and, on production, to the IP addresses on your dashboard allowlist when one is configured.
Headers
The merchant customer this request acts on behalf of.
Path Parameters
The escrow's payment token (e.g. PY_8AB12C9D3045).
Body
Naira with at most two decimal places. Minimum 1000. Must equal the sum of the milestone amounts.
x >= 10001000000
"Company website build"
For milestone escrows the buyer always pays the Payluk fee; buyer is the only accepted value.
buyer "buyer"
Length of the delivery window, in deliveryTimeline units. Required. Between 1 and 365.
1 <= x <= 36530
Unit for maxDelivery. Required.
minutes, hours, days "days"
At least 2 milestones whose amounts sum to amount.
2Show child attributes
Show child attributes
"3-phase delivery"
1
"665f1b2c9a1e4d0012ab3c30"