curl --request POST \
--url https://tapipay-facade.homo.tapila.cloud/payment-links \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--header 'x-authorization-token: <api-key>' \
--data '
{
"amount": 1.01,
"description": "<string>",
"expiresAt": "2026-12-31T23:59:59Z",
"currency": "MXN",
"externalPaymentLinkId": "<string>",
"successUrl": "<string>",
"singleUse": true,
"metadata": {},
"externalClientId": "<string>",
"productName": "<string>",
"identifierValue": "<string>",
"additionalData": {
"source": "crm",
"folio": "F-2026-0042"
}
}
'import requests
url = "https://tapipay-facade.homo.tapila.cloud/payment-links"
payload = {
"amount": 1.01,
"description": "<string>",
"expiresAt": "2026-12-31T23:59:59Z",
"currency": "MXN",
"externalPaymentLinkId": "<string>",
"successUrl": "<string>",
"singleUse": True,
"metadata": {},
"externalClientId": "<string>",
"productName": "<string>",
"identifierValue": "<string>",
"additionalData": {
"source": "crm",
"folio": "F-2026-0042"
}
}
headers = {
"x-api-key": "<api-key>",
"x-authorization-token": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-api-key': '<api-key>',
'x-authorization-token': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: 1.01,
description: '<string>',
expiresAt: '2026-12-31T23:59:59Z',
currency: 'MXN',
externalPaymentLinkId: '<string>',
successUrl: '<string>',
singleUse: true,
metadata: {},
externalClientId: '<string>',
productName: '<string>',
identifierValue: '<string>',
additionalData: {source: 'crm', folio: 'F-2026-0042'}
})
};
fetch('https://tapipay-facade.homo.tapila.cloud/payment-links', 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://tapipay-facade.homo.tapila.cloud/payment-links",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'amount' => 1.01,
'description' => '<string>',
'expiresAt' => '2026-12-31T23:59:59Z',
'currency' => 'MXN',
'externalPaymentLinkId' => '<string>',
'successUrl' => '<string>',
'singleUse' => true,
'metadata' => [
],
'externalClientId' => '<string>',
'productName' => '<string>',
'identifierValue' => '<string>',
'additionalData' => [
'source' => 'crm',
'folio' => 'F-2026-0042'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>",
"x-authorization-token: <api-key>"
],
]);
$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://tapipay-facade.homo.tapila.cloud/payment-links"
payload := strings.NewReader("{\n \"amount\": 1.01,\n \"description\": \"<string>\",\n \"expiresAt\": \"2026-12-31T23:59:59Z\",\n \"currency\": \"MXN\",\n \"externalPaymentLinkId\": \"<string>\",\n \"successUrl\": \"<string>\",\n \"singleUse\": true,\n \"metadata\": {},\n \"externalClientId\": \"<string>\",\n \"productName\": \"<string>\",\n \"identifierValue\": \"<string>\",\n \"additionalData\": {\n \"source\": \"crm\",\n \"folio\": \"F-2026-0042\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("x-authorization-token", "<api-key>")
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.post("https://tapipay-facade.homo.tapila.cloud/payment-links")
.header("x-api-key", "<api-key>")
.header("x-authorization-token", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": 1.01,\n \"description\": \"<string>\",\n \"expiresAt\": \"2026-12-31T23:59:59Z\",\n \"currency\": \"MXN\",\n \"externalPaymentLinkId\": \"<string>\",\n \"successUrl\": \"<string>\",\n \"singleUse\": true,\n \"metadata\": {},\n \"externalClientId\": \"<string>\",\n \"productName\": \"<string>\",\n \"identifierValue\": \"<string>\",\n \"additionalData\": {\n \"source\": \"crm\",\n \"folio\": \"F-2026-0042\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://tapipay-facade.homo.tapila.cloud/payment-links")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["x-authorization-token"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"amount\": 1.01,\n \"description\": \"<string>\",\n \"expiresAt\": \"2026-12-31T23:59:59Z\",\n \"currency\": \"MXN\",\n \"externalPaymentLinkId\": \"<string>\",\n \"successUrl\": \"<string>\",\n \"singleUse\": true,\n \"metadata\": {},\n \"externalClientId\": \"<string>\",\n \"productName\": \"<string>\",\n \"identifierValue\": \"<string>\",\n \"additionalData\": {\n \"source\": \"crm\",\n \"folio\": \"F-2026-0042\"\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"paymentLinkId": "plk_61a837f5-3c67-423a-ade7-94b78e0007cb",
"status": "ACTIVE",
"amount": 4500,
"currency": "MXN",
"description": "Factura única #777",
"singleUse": true,
"paymentUrl": "https://app.tapipay.la/s/acme-corp/portal/McXmbnKaju/debts/payment-methods?externalRequestId=pl-debt-FAC-777",
"createdAt": "2026-06-03T19:20:00.000Z",
"debtId": "debt_pl-debt-FAC-777",
"externalPaymentLinkId": "FAC-777",
"expiresAt": "2026-06-30T23:59:59.000Z",
"successUrl": null,
"metadata": null,
"identifierValue": "acm-x3kM9pQr",
"contact": null,
"product": null
},
"requestId": "<string>"
}Crear link de pago
Genera una liga de pago para cobrar sin conocer al deudor de antemano.
curl --request POST \
--url https://tapipay-facade.homo.tapila.cloud/payment-links \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--header 'x-authorization-token: <api-key>' \
--data '
{
"amount": 1.01,
"description": "<string>",
"expiresAt": "2026-12-31T23:59:59Z",
"currency": "MXN",
"externalPaymentLinkId": "<string>",
"successUrl": "<string>",
"singleUse": true,
"metadata": {},
"externalClientId": "<string>",
"productName": "<string>",
"identifierValue": "<string>",
"additionalData": {
"source": "crm",
"folio": "F-2026-0042"
}
}
'import requests
url = "https://tapipay-facade.homo.tapila.cloud/payment-links"
payload = {
"amount": 1.01,
"description": "<string>",
"expiresAt": "2026-12-31T23:59:59Z",
"currency": "MXN",
"externalPaymentLinkId": "<string>",
"successUrl": "<string>",
"singleUse": True,
"metadata": {},
"externalClientId": "<string>",
"productName": "<string>",
"identifierValue": "<string>",
"additionalData": {
"source": "crm",
"folio": "F-2026-0042"
}
}
headers = {
"x-api-key": "<api-key>",
"x-authorization-token": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-api-key': '<api-key>',
'x-authorization-token': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: 1.01,
description: '<string>',
expiresAt: '2026-12-31T23:59:59Z',
currency: 'MXN',
externalPaymentLinkId: '<string>',
successUrl: '<string>',
singleUse: true,
metadata: {},
externalClientId: '<string>',
productName: '<string>',
identifierValue: '<string>',
additionalData: {source: 'crm', folio: 'F-2026-0042'}
})
};
fetch('https://tapipay-facade.homo.tapila.cloud/payment-links', 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://tapipay-facade.homo.tapila.cloud/payment-links",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'amount' => 1.01,
'description' => '<string>',
'expiresAt' => '2026-12-31T23:59:59Z',
'currency' => 'MXN',
'externalPaymentLinkId' => '<string>',
'successUrl' => '<string>',
'singleUse' => true,
'metadata' => [
],
'externalClientId' => '<string>',
'productName' => '<string>',
'identifierValue' => '<string>',
'additionalData' => [
'source' => 'crm',
'folio' => 'F-2026-0042'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>",
"x-authorization-token: <api-key>"
],
]);
$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://tapipay-facade.homo.tapila.cloud/payment-links"
payload := strings.NewReader("{\n \"amount\": 1.01,\n \"description\": \"<string>\",\n \"expiresAt\": \"2026-12-31T23:59:59Z\",\n \"currency\": \"MXN\",\n \"externalPaymentLinkId\": \"<string>\",\n \"successUrl\": \"<string>\",\n \"singleUse\": true,\n \"metadata\": {},\n \"externalClientId\": \"<string>\",\n \"productName\": \"<string>\",\n \"identifierValue\": \"<string>\",\n \"additionalData\": {\n \"source\": \"crm\",\n \"folio\": \"F-2026-0042\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("x-authorization-token", "<api-key>")
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.post("https://tapipay-facade.homo.tapila.cloud/payment-links")
.header("x-api-key", "<api-key>")
.header("x-authorization-token", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": 1.01,\n \"description\": \"<string>\",\n \"expiresAt\": \"2026-12-31T23:59:59Z\",\n \"currency\": \"MXN\",\n \"externalPaymentLinkId\": \"<string>\",\n \"successUrl\": \"<string>\",\n \"singleUse\": true,\n \"metadata\": {},\n \"externalClientId\": \"<string>\",\n \"productName\": \"<string>\",\n \"identifierValue\": \"<string>\",\n \"additionalData\": {\n \"source\": \"crm\",\n \"folio\": \"F-2026-0042\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://tapipay-facade.homo.tapila.cloud/payment-links")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["x-authorization-token"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"amount\": 1.01,\n \"description\": \"<string>\",\n \"expiresAt\": \"2026-12-31T23:59:59Z\",\n \"currency\": \"MXN\",\n \"externalPaymentLinkId\": \"<string>\",\n \"successUrl\": \"<string>\",\n \"singleUse\": true,\n \"metadata\": {},\n \"externalClientId\": \"<string>\",\n \"productName\": \"<string>\",\n \"identifierValue\": \"<string>\",\n \"additionalData\": {\n \"source\": \"crm\",\n \"folio\": \"F-2026-0042\"\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"paymentLinkId": "plk_61a837f5-3c67-423a-ade7-94b78e0007cb",
"status": "ACTIVE",
"amount": 4500,
"currency": "MXN",
"description": "Factura única #777",
"singleUse": true,
"paymentUrl": "https://app.tapipay.la/s/acme-corp/portal/McXmbnKaju/debts/payment-methods?externalRequestId=pl-debt-FAC-777",
"createdAt": "2026-06-03T19:20:00.000Z",
"debtId": "debt_pl-debt-FAC-777",
"externalPaymentLinkId": "FAC-777",
"expiresAt": "2026-06-30T23:59:59.000Z",
"successUrl": null,
"metadata": null,
"identifierValue": "acm-x3kM9pQr",
"contact": null,
"product": null
},
"requestId": "<string>"
}Autorizaciones
API key del API Gateway de Tapi. Requerida en todas las operaciones. Distinta por ambiente (desarrollo, homologación, producción).
Token TAPI JWT. Requerido en todas las operaciones. Se envía sin prefijo "Bearer". Ej: x-authorization-token: eyJhbGci...
Encabezados
Clave de idempotencia (opcional). Si no se envía externalPaymentLinkId en el body, el valor del header se usa como externalPaymentLinkId; si se envían los dos, el header se ignora. Repetir un externalPaymentLinkId devuelve 409 RESOURCE_CONFLICT y no se crea ninguna deuda. Sin ninguno de los dos, el link no tiene llave externa (externalPaymentLinkId es null en la respuesta).
Cuerpo
Los campos no declarados se ignoran.
Monto en pesos (hasta 2 decimales, mínimo 0.01)
x >= 0.01Debe ser un múltiplo de 0.01Descripción visible en la página de pago. Debe ser string (si no, 400).
Fecha/hora de expiración, obligatoria. Debe ser un date-time RFC 3339 (con Z u offset) y estar en el futuro; 2026-12-31 23:59 o solo fecha devuelven 400. Se convierte y guarda en UTC. El vencimiento de la deuda asociada es la fecha UTC de expiresAt.
"2026-12-31T23:59:59Z"
Código de moneda ISO 4217 (MXN, ARS, PEN, COP, CLP, USD). Default MXN.
MXN, ARS, PEN, COP, CLP, USD Llave natural del link. Única por organización. Usada para idempotencia y matching externo. Si no se envía, se usa el header Idempotency-Key. Si no hay ninguno de los dos, el link no tiene llave externa: en la respuesta externalPaymentLinkId es null y el debtId usa el UUID del link (debt_pl-debt-<uuid>). Repetirla devuelve 409 RESOURCE_CONFLICT y no se crea ninguna deuda.
URL de redirección al completar el pago (opcional)
Si true, el link se desactiva tras el primer pago. Si false, acepta múltiples pagos (reutilizable). Default true.
Metadatos arbitrarios del cliente (opcional). Objeto plano.
Identificador del deudor (cliente conocido). Mutuamente excluyente con contactData. Si se proporciona, la API resuelve el contacto existente por externalClientId en la organización. Si no corresponde a un contacto existente, la API responde 422 BUSINESS_RULE_VIOLATION y no se crea nada; para crear el contacto en el mismo request usa contactData.
Datos del deudor inline. Mutuamente excluyente con externalClientId. Si se proporciona, se crea un nuevo contacto (o se reutiliza si externalClientId ya existe).
Show child attributes
Show child attributes
Nombre del producto a asociar (opcional). Se resuelve por name o se crea inline si no existe. Identificado por name único por companyCode.
Identificador explícito del link de pago (opcional). Si se proporciona, se sanitiza a URL-safe (alfanumérico + guiones, lowercase, máx 64 chars). Si tras sanear queda vacío, retorna 400 INVALID_REQUEST. Precedencia de resolución: identifierValue explícito > externalClientId (deudor) > sintético. Si se envía identifierValue: se usa ese valor (saneado). Si NO se envía y hay deudor conocido (externalClientId/contactData): se usa el identificador del deudor. Si NO se envía y NO hay deudor: se genera sintético {3letras}-{random}. Exposición en respuesta (PII-safe): SIN deudor conocido (anónimo/reutilizable) se expone identifierValue en respuesta. CON deudor conocido: se devuelve null, incluso si el cliente mandó identifierValue explícito.
64Objeto plano con las mismas claves reservadas que en deudas. Se guarda en la deuda asociada al link; no se devuelve en el link.
{ "source": "crm", "folio": "F-2026-0042" }
Respuesta
Link de pago creado
externalPaymentLinkId, expiresAt, successUrl, metadata, identifierValue, contact y product siempre vienen, con null cuando no hay valor.
Show child attributes
Show child attributes
{
"paymentLinkId": "plk_61a837f5-3c67-423a-ade7-94b78e0007cb",
"status": "ACTIVE",
"amount": 4500,
"currency": "MXN",
"description": "Factura única #777",
"singleUse": true,
"paymentUrl": "https://app.tapipay.la/s/acme-corp/portal/McXmbnKaju/debts/payment-methods?externalRequestId=pl-debt-FAC-777",
"createdAt": "2026-06-03T19:20:00.000Z",
"debtId": "debt_pl-debt-FAC-777",
"externalPaymentLinkId": "FAC-777",
"expiresAt": "2026-06-30T23:59:59.000Z",
"successUrl": null,
"metadata": null,
"identifierValue": "acm-x3kM9pQr",
"contact": null,
"product": null
}

