Convenciones

Formatos, idempotencia, paginación, errores y límites de uso de la API v1.

Actualizado:

Lo básico

  • URL base https://api.wagend.app/v1. Los cambios incompatibles salen como una nueva versión; los cambios aditivos (campos nuevos) pueden llegar en cualquier momento, así que ignorá los campos que no conozcas.
  • JSON de entrada y de salida (Content-Type: application/json).
  • Fechas en ISO 8601 con offset (2026-10-15T09:45:00-03:00). Se guardan en UTC.
  • Montos en centavos enteros más currency (BRL, ARS, PYG, USD).
  • Los IDs son strings opacos. Los campos sin valor llegan como null explícito.
  • El contrato legible por máquina es packages/openapi/openapi.yaml (OpenAPI 3.1) y el historial de cambios resume lo nuevo.

Idempotencia

POST /holds, POST /holds/{id}/confirm, POST /bookings, POST /bookings/{id}/reschedule y POST /bookings/{id}/actions/{key} llevan el header Idempotency-Key (por ejemplo un UUID). Repetir un request con la misma clave dentro de 24 horas devuelve la respuesta original. Reusar la clave con otro body devuelve 422 con code: "idempotency_conflict".

POST /customers acepta Idempotency-Key de forma opcional. POST /webhook-endpoints no lo admite, porque su respuesta contiene el secreto.

Paginación

Los endpoints de listado usan cursores:

curl "https://api.wagend.app/v1/bookings?limit=50" -H "Authorization: Bearer $WAGEND_KEY"
# → { "data": [...], "next_cursor": "eyJpZCI6..." }
curl "https://api.wagend.app/v1/bookings?limit=50&cursor=eyJpZCI6..." -H "Authorization: Bearer $WAGEND_KEY"

Cuando next_cursor es null, no hay más páginas.

Errores

Los errores siguen la RFC 9457 (application/problem+json):

{
  "type": "https://fiuit.com/docs/api/conventions#errors",
  "title": "Slot no longer available",
  "status": 409,
  "code": "slot_taken",
  "alternatives": [{ "start": "2026-10-15T10:15:00-03:00", "end": "2026-10-15T10:45:00-03:00" }]
}
codeEstadoCuándo
validation_error422Falló la validación del body o de los parámetros
invalid_api_key401Clave ausente, inválida o revocada
idempotency_key_required400Falta el header Idempotency-Key en una operación que lo exige
version_conflict409Alguien editó antes el mismo recurso (versión desactualizada)
insufficient_scope403La clave no tiene el scope
not_found404Id desconocido (o de otro proyecto)
slot_taken409Otra persona tomó el horario
already_claimed409Otra persona del equipo tomó antes la tarea de cola
customer_exists409Ya hay un cliente con ese teléfono
invalid_transition409Por ejemplo confirmar una reserva cancelada
hold_expired410La pre-reserva venció antes de confirmar
idempotency_conflict422Misma clave, distinto body
rate_limited429Demasiados requests

Cada respuesta de error trae code: usalo para decidir qué hacer, no el texto del title.

Límites de uso

Los límites aplican por clave y por proyecto (un cubo con ráfaga de 120 requests y recarga de 2 por segundo). Cada respuesta trae RateLimit-Limit, RateLimit-Remaining y RateLimit-Reset. Ante un 429, esperá Retry-After segundos.