Update Pay Link
Update the details of a specific payment link.
POST
https://dev.mytpe.app/api/v2/mytpe-pay/links/update/{id}Updates the details of an existing payment link.
Authentication: API Key (X-API-KEY + X-API-SECRET headers)
Update Logic & Constraints
The ability to update a link depends heavily on its Current Status and Payment Mode.
Strict Rules
- One-Shot Links: Cannot be updated once created. They are immutable.
- Mode Switching: You cannot change the
payment_modeortype(e.g., switching fromlimitedtoreusableis forbidden). - Restocking: If a
limitedlink is Closed (sold out), you can only update it if you increase themax_payments. This will automatically reopen the link.
Body Parameters
Prop
Type
Updating Settings
You can update link behavior settings via the settings object. Settings are merged with existing values — you only need to send the keys you want to change.
Prop
Type
Form-data format
settings[show_retry_button]:false
settings[allow_anonymous]:trueExample: Disable Retry Button on an Existing Link
const linkId = 'link-demo-123';
const form = new FormData();
form.append('settings[show_retry_button]', 'false');
const response = await fetch(
`https://dev.mytpe.app/api/v2/mytpe-pay/links/update/${linkId}`,
{
method: 'POST',
headers: {
'X-API-KEY': 'your_api_key',
'X-API-SECRET': 'your_api_secret',
},
body: form,
}
);This will disable the "Retry Payment" button on the payment results page for this link. Other settings remain unchanged.
Example: Enable Anonymous Payments on an Existing Link
const linkId = 'link-demo-123';
const form = new FormData();
form.append('settings[allow_anonymous]', 'true');
const response = await fetch(
`https://dev.mytpe.app/api/v2/mytpe-pay/links/update/${linkId}`,
{
method: 'POST',
headers: {
'X-API-KEY': 'your_api_key',
'X-API-SECRET': 'your_api_secret',
},
body: form,
}
);After this update, the checkout page will show an "Anonymous payment" checkbox. Customers can opt to pay without providing personal information. Other settings remain unchanged.
Updating UDFs
New Feature
You can update the User-Defined Fields (UDFs) attached to a payment link. UDFs are custom data fields sent to the payment gateway with every payment on this link. Each UDF value must be alphanumeric only (letters and numbers, max 20 characters) — no special characters or spaces allowed.
Full Replacement
Unlike metadata (which merges), updating udfs replaces all UDFs entirely. If you only send udf2, any previously set udf1, udf3–udf5 will be removed. To keep existing UDFs, include them in the update request.
udf1 — Bank Receipt Field
udf1 is special: its value is displayed on the bank payment receipt, making it ideal for reconciliation references (e.g., invoice number, order ID). If you don't set udf1, the system auto-generates an order number for it. The other UDFs (udf2–udf5) are only stored on the SATIM platform and MyTPE — they do not appear on the receipt.
Form-data format
udfs[udf1][value]:INV2026999
udfs[udf1][label]:Invoice Number
udfs[udf2][value]:JaneSmith
udfs[udf2][label]:Customer NameSet udfs to empty to clear all UDFs from a link.
Updating Inactivity Expiry
The per-link inactivity timeout (inactivity_timeout_minutes) controls how long a one_shot or limited link stays active without successful payments before being auto-closed (status → expired). See the Pay Links Overview for the full conceptual explanation.
Three valid actions
Set an override: send a positive integer (e.g. 30) to override the instance default for this specific link.
Clear the override: send an empty value (form-data: inactivity_timeout_minutes:) to revert this link to the instance default.
Leave unchanged: simply omit inactivity_timeout_minutes from the request body.
Reusable mode is ignored
Sending inactivity_timeout_minutes on a reusable link has no effect — reusable links never inactivity-expire by design.
Form-data format
inactivity_timeout_minutes:30(Sets a 30-minute override on this link)
inactivity_timeout_minutes:(Empty value — clears the override and reverts to the instance default)
Example: Override an existing link to 15 minutes
const linkId = 'link-demo-123';
const form = new FormData();
form.append('_method', 'PATCH');
form.append('inactivity_timeout_minutes', '15');
const response = await fetch(
`https://dev.mytpe.app/api/v2/mytpe-pay/links/update/${linkId}`,
{
method: 'POST',
headers: {
'X-API-KEY': 'your_api_key',
'X-API-SECRET': 'your_api_secret',
},
body: form,
}
);Example: Revert a link to the instance default
const linkId = 'link-demo-123';
const form = new FormData();
form.append('_method', 'PATCH');
form.append('inactivity_timeout_minutes', ''); // empty = clear override
const response = await fetch(
`https://dev.mytpe.app/api/v2/mytpe-pay/links/update/${linkId}`,
{
method: 'POST',
headers: {
'X-API-KEY': 'your_api_key',
'X-API-SECRET': 'your_api_secret',
},
body: form,
}
);Example Request
const linkId = 'link-demo-123';
const form = new FormData();
form.append('_method', 'PATCH');
form.append('max_payments', '100');
form.append('title', 'Concert Ticket (Batch 2)');
form.append('udfs[udf2][value]', 'TICKETBATCH2');
form.append('udfs[udf2][label]', 'Batch Reference');
const response = await fetch(
`https://dev.mytpe.app/api/v2/mytpe-pay/links/update/${linkId}`,
{
method: 'POST',
headers: {
'X-API-KEY': 'your_api_key',
'X-API-SECRET': 'your_api_secret',
},
body: form,
}
);
const data = await response.json();
console.log(data);interface UpdatePayLinkResponse {
success: boolean;
message: string;
data: {
id: string;
title: string;
amount: string;
status: string;
payment_mode: string;
max_payments: number;
successful_payments_count: number;
remaining_payments: number;
};
}
const linkId = 'link-demo-123';
const form = new FormData();
form.append('_method', 'PATCH');
form.append('max_payments', '100');
form.append('title', 'Concert Ticket (Batch 2)');
form.append('udfs[udf2][value]', 'TICKETBATCH2');
form.append('udfs[udf2][label]', 'Batch Reference');
const response = await fetch(
`https://dev.mytpe.app/api/v2/mytpe-pay/links/update/${linkId}`,
{
method: 'POST',
headers: {
'X-API-KEY': 'your_api_key',
'X-API-SECRET': 'your_api_secret',
},
body: form,
}
);
const data: UpdatePayLinkResponse = await response.json();
console.log(data);import requests
link_id = 'link-demo-123'
url = f'https://dev.mytpe.app/api/v2/mytpe-pay/links/update/{link_id}'
headers = {
'X-API-KEY': 'your_api_key',
'X-API-SECRET': 'your_api_secret',
}
payload = {
'_method': 'PATCH',
'max_payments': '100',
'title': 'Concert Ticket (Batch 2)',
'udfs[udf2][value]': 'TICKETBATCH2',
'udfs[udf2][label]': 'Batch Reference',
}
response = requests.post(url, headers=headers, data=payload)
data = response.json()
print(data)use Illuminate\Support\Facades\Http;
$linkId = 'link-demo-123';
$response = Http::asMultipart()
->withHeaders([
'X-API-KEY' => 'your_api_key',
'X-API-SECRET' => 'your_api_secret',
])
->post("https://dev.mytpe.app/api/v2/mytpe-pay/links/update/{$linkId}", [
'_method' => 'PATCH',
'max_payments' => 100,
'title' => 'Concert Ticket (Batch 2)',
'udfs' => [
'udf2' => ['value' => 'TICKETBATCH2', 'label' => 'Batch Reference'],
],
]);
$data = $response->json();<?php
$linkId = 'link-demo-123';
$curl = curl_init();
$boundary = uniqid();
$delimiter = '-------------' . $boundary;
$fields = [
'_method' => 'PATCH',
'max_payments' => '100',
'title' => 'Concert Ticket (Batch 2)',
'udfs[udf1][value]' => 'TICKETBATCH2',
'udfs[udf1][label]' => 'Batch Reference',
];
$postData = '';
foreach ($fields as $name => $value) {
$postData .= "--{$delimiter}\r\n";
$postData .= "Content-Disposition: form-data; name=\"{$name}\"\r\n\r\n";
$postData .= "{$value}\r\n";
}
$postData .= "--{$delimiter}--\r\n";
curl_setopt_array($curl, [
CURLOPT_URL => "https://dev.mytpe.app/api/v2/mytpe-pay/links/update/{$linkId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $postData,
CURLOPT_HTTPHEADER => [
'X-API-KEY: your_api_key',
'X-API-SECRET: your_api_secret',
'Content-Type: multipart/form-data; boundary=' . $delimiter,
],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;const axios = require('axios');
const FormData = require('form-data');
const linkId = 'link-demo-123';
const form = new FormData();
form.append('_method', 'PATCH');
form.append('max_payments', '100');
form.append('title', 'Concert Ticket (Batch 2)');
form.append('udfs[udf2][value]', 'TICKETBATCH2');
form.append('udfs[udf2][label]', 'Batch Reference');
axios.post(
`https://dev.mytpe.app/api/v2/mytpe-pay/links/update/${linkId}`,
form,
{
headers: {
...form.getHeaders(),
'X-API-KEY': 'your_api_key',
'X-API-SECRET': 'your_api_secret',
},
}
)
.then(response => console.log(response.data))
.catch(error => console.error(error.response?.data));Example Success Response (200 OK)
200 OK
{
"success": true,
"message": "Pay link updated successfully",
"data": {
"id": "link-demo-123",
"mytpe_pay_id": "instance-001",
"title": "Updated Product Title",
"details": "Updated detailed description.",
"logo": null,
"slug": "demo-product",
"type": "dynamic",
"amount": "2500.00",
"status": "active",
"payment_mode": "limited",
"max_payments": 100,
"successful_payments_count": 15,
"metadata": {
"order_id": "ORD-456",
"customer_type": "premium"
},
"udfs": {
"udf1": { "value": "BATCH2REF", "label": "Batch Reference" },
"udf2": { "value": "TICKETBATCH2", "label": "Ticket ID" }
},
"settings": {
"show_retry_button": true
},
"created_at": "2026-01-01T00:00:00.000Z",
"updated_at": "2026-01-17T10:00:00.000Z",
"payment_link": "https://frontdev.mytpe.app/pay/demo-product",
"remaining_payments": 85
}
}Error Responses
422 Validation Error
{
"message": "The given data was invalid.",
"errors": {
"max_payments": ["The limit (40) cannot be lower than the 50 payments already received."]
}
}403 Forbidden Action
{
"message": "One-shot links cannot be updated."
}