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

CampoTipoDescripción
authentication_error401Falta la llave (missing_api_key) o no es válida/está revocada (invalid_api_key).
permission_error403activation_required: tu cuenta aún no tiene los cobros activados.
invalid_request_error400invalid_json o invalid_parameters. Revisa details.
not_found_error404resource_missing: el id no existe o no pertenece a tu cuenta. No distinguimos los dos casos a propósito.
conflict_error409 · 402El 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_error429Superaste las 120 peticiones por minuto de la llave.
api_error500Algo 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-Key y reintenta con la misma llave — te devolvemos el mismo cobro, no uno nuevo. Si respondemos 409 idempotency_unresolved, la original se cortó a medias y no sabemos si el dinero se movió: consulta GET /v1/payments antes 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_after y 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"