MyTPE is getting a fresh new look! A simpler, faster platform is on the way. Learn more →
MyTPEMyTPE Pay
Pay Links

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

  1. One-Shot Links: Cannot be updated once created. They are immutable.
  2. Mode Switching: You cannot change the payment_mode or type (e.g., switching from limited to reusable is forbidden).
  3. Restocking: If a limited link is Closed (sold out), you can only update it if you increase the max_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]:true
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.

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, udf3udf5 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 (udf2udf5) 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 Name

Set 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)

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,
  }
);
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

update-pay-link.js
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);
update-pay-link.ts
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);
update_pay_link.py
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)
UpdatePayLinkController.php
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();
update-pay-link.php
<?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;
update-pay-link.cjs
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."
}

On this page