Errores y paginación
Todos los errores tienen la misma forma y todos los listados se paginan igual. Si programas contra estas dos convenciones, el resto de la API es predecible.
Forma del error
400 Bad Request
{
"error": {
"type": "invalid_request_error",
"code": "invalid_parameters",
"message": "Hay parámetros inválidos.",
"details": {
"amount": ["Number must be greater than 0"]
}
}
}Programa contra error.code (estable), no contra message (está en español y puede cambiar). details solo aparece cuando hay información extra útil, como los campos que fallaron.
Tipos y códigos HTTP
| Campo | Tipo | Descripción |
|---|---|---|
authentication_error | 401 | Falta la llave (missing_api_key) o no es válida/está revocada (invalid_api_key). |
permission_error | 403 | activation_required: tu cuenta aún no tiene los cobros activados. |
invalid_request_error | 400 | invalid_json o invalid_parameters. Revisa details. |
not_found_error | 404 | resource_missing: el id no existe o no pertenece a tu cuenta. No distinguimos los dos casos a propósito. |
conflict_error | 409 · 402 | El objeto existe pero no admite la operación: customer_exists, link_completed, no_saved_card, o charge_declined (402, el banco rechazó la tarjeta). |
rate_limit_error | 429 | Superaste las 120 peticiones por minuto de la llave. |
api_error | 500 | Algo falló de nuestro lado. Reintenta; si persiste, escríbenos. |
Qué reintentar
- 429 y 5xx: reintenta con espera progresiva (1s, 2s, 4s…).
- 4xx (salvo 429): no reintentes, la petición está mal formada o el estado no lo permite. Corrige y vuelve a mandar.
- Timeouts de red en un cobro: manda
Idempotency-Keyy reintenta con la misma llave — te devolvemos el mismo cobro, no uno nuevo. Si respondemos409 idempotency_unresolved, la original se cortó a medias y no sabemos si el dinero se movió: consultaGET /v1/paymentsantes de reintentar, con una llave nueva. - Timeouts en los demás POST: ahí todavía no hay llave de idempotencia, así que consulta antes de repetir — por ejemplo, lista los links por
created_aftery busca el tuyo.
Paginación
Los listados devuelven un objeto list con cursor. Pide ?limit= (1–100, por defecto 25) y para la siguiente página manda ?starting_after= con el next_cursor que recibiste.
GET /v1/payments?limit=2
{
"object": "list",
"data": [ { "object": "payment", "id": "cmqbbf…" }, { "object": "payment", "id": "cmqbb2…" } ],
"has_more": true,
"next_cursor": "cmqbb2yrb0009jy7ywx8njt0a"
}Recorrer todo (Node.js)
async function* allPayments(key) {
let cursor = null;
do {
const url = new URL("https://go.paytiptap.com/api/v1/payments");
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("starting_after", cursor);
const res = await fetch(url, { headers: { Authorization: `Bearer ${key}` } });
const page = await res.json();
yield* page.data;
cursor = page.has_more ? page.next_cursor : null;
} while (cursor);
}Filtros de fecha
Los listados de pagos y links aceptan created_after y created_before en ISO‑8601. Los resultados siempre vienen del más reciente al más antiguo.
curl
curl "https://go.paytiptap.com/api/v1/payments?status=APPROVED&created_after=2026-07-01T00:00:00Z" \
-H "Authorization: Bearer tiptap_sk_TU_LLAVE"