Stable Pro

Stable Pro API · v1

Convenciones

Importes, fechas, códigos, impuestos, listas y filtros, idiomas, versiones.

Solicitudes y respuestas

GET lee. Las respuestas son JSON, con los nombres de los campos en inglés y en snake_case. Cada respuesta lleva Cache-Control: no-store. Cada objeto tiene un campo object que dice qué es (charge, payment, event…).

Importes

Los importes son enteros en la unidad menor de su moneda (ISO 4217), con la moneda al lado: 300,00 € es 30000 con currency: "EUR"; 3.000 ¥ es 3000; 25,500 KWD es 25500.

Cada importe es el total que paga el cliente (amount_basis: "gross"): cuando Stable Pro calcula el IVA, el total lo incluye, y Stable Pro da al lado la base imponible y el impuesto. Un programa que aplica su propio impuesto a un importe de Stable Pro lo deriva de ese total, no lo suma.

Los importes llevan signo donde importa la dirección: una corrección que reduce un cargo es negativa, un reembolso es negativo.

Fechas

  • Las fechas de calendario (vencimientos, periodos, la fecha de un cobro) son YYYY-MM-DD; los meses son YYYY-MM.
  • Los instantes (created_at, issued_at, occurred_at…) son RFC 3339 en UTC: 2026-11-10T14:32:05.120Z.
  • El mes contable (accounting_month) lo calcula Stable Pro en la zona horaria de la cuadra: es el posterior entre el mes de devengo y el mes en que se registró el hecho. Nunca necesitas hacer un cálculo de zona horaria.

La zona horaria, la moneda, el país y el idioma de la cuadra están en GET /organization.

Códigos, no textos

El contrato expone códigos — action, reason, category, origin, los tipos de cargo, los tipos de evento — nunca frases en un idioma. Los nombres para las personas vienen del diccionario, en el idioma solicitado:

curl "https://app.stable-pro.com/api/v1/codes?lang=de" -H "Authorization: Bearer sp_live_…"

GET /codes enumera cada familia de códigos, dónde aparece cada familia (fields, por ejemplo adjustment.reason) y un name por código. El nombre de un reason depende de su action: búscalo con los dos.

Las listas de códigos son abiertas: un valor nuevo puede llegar dentro de la v1. Tu integración debe aceptar un código que aún no conoce (y puede leer su nombre en /codes). taxonomy_version dice qué versión de la taxonomía de correcciones produjo una fila.

Donde existe una lista estándar, se usa esa: moneda ISO 4217, país ISO 3166-1 y subdivisión ISO 3166-2 (IT-MI, US-OH), identificadores fiscales con un esquema ISO 6523, categoría de impuesto UNCL 5305 (S, Z, E, AE, K, G, O), unidades UNECE Rec. 20 (MON, ANN, C62).

Impuestos

Cada cargo y cada corrección indican:

  • tax_calculated_by: stable_pro (Stable Pro calcula el IVA y lo da), o external — que solo significa que Stable Pro no lo calcula: no significa que el impuesto sea cero;
  • tax_treatment: standard_rated, zero_rated, not_calculated o undetermined (un hecho más antiguo del que no se sabe);
  • taxable_amount y taxes[]: una lista, incluso con un solo elemento — { type, jurisdiction, category, rate_bp, amount }. Los tipos impositivos están en puntos básicos: el 22 % es 2200.

Un cargo se lee tal como es ahora: su importe y sus impuestos son su origen, más sus correcciones, más cualquier cambio de impuesto posterior.

Listas

Una lista contiene todos los hechos de su tipo, pagados o no: GET /charges son todos los cargos a los clientes (nunca los pagos al personal), GET /customers son todos los que tienen al menos un cargo, socios o personal.

Las listas funcionan con cursor:

GET /charges?limit=100&starting_after=<id del último elemento que leíste>
  • limit de 1 a 100 (25 si falta);
  • el sobre es { "object": "list", "data": [...], "has_more": true }; vuelve a pedir con starting_after = el id del último elemento;
  • el orden es siempre desde el más antiguo: created_at, luego id (recibos: issued_at, luego id).

Filtros

Algunas listas se pueden acotar con filtros, que se aplican todos juntos, con limit y con el cursor. Por ejemplo, los cargos de un cliente en un mes:

GET /charges?customer=<id del cliente>&accounting_month=2026-10
ListaFiltros
GET /chargescustomer, accounting_month
GET /adjustmentscharge, accounting_month
GET /paymentscustomer
GET /credit-entriescustomer
GET /receiptscustomer, payment

customer, charge y payment llevan un id; accounting_month lleva YYYY-MM y es el mes contable, el mes en que cuenta el hecho (consulta «Fechas» más arriba).

Parámetros desconocidos y valores no válidos

Un parámetro que el endpoint no conoce nunca se ignora: la respuesta es 400 invalid-request, e invalid_param dice cuál. Así, un filtro mal escrito (accountingmonth en lugar de accounting_month) nunca devuelve la lista entera. Lo mismo vale para un limit, un cursor o un filtro con un valor no válido. La clave y los permisos se comprueban antes: sin clave la respuesta sigue siendo 401, sin el permiso 403.

Las listas sirven para buscar y comprobar; para mantenerte sincronizado, lee los eventos (Eventos).

Idiomas

El contrato está en inglés y nunca cambia con el idioma. Las frases para las personas — el detail de un error, los nombres en /codes — llegan en el idioma solicitado: ?lang= prevalece sobre Accept-Language; sin ninguno de los dos, inglés. Disponibles: en, it, fr, de, es. La respuesta indica el idioma en Content-Language.

Versiones

La versión está en la ruta: /api/v1/. Dentro de la v1 solo hay añadidos: un campo nuevo, un endpoint nuevo, un valor nuevo de una lista de códigos. Todo lo que rompería una integración es una v2, con al menos un año de convivencia y las cabeceras Deprecation y Sunset.

Los recibos no son documentos fiscales

Los recibos de Stable Pro confirman un pago (fiscal_document: false). El documento fiscal lo emite tu programa. La cuadra puede elegir no dar los recibos de Stable Pro a sus clientes mientras tu programa esté conectado: GET /organization lo indica en receipts_shown_to_customers. Los recibos siguen existiendo, numerados, y puedes leerlos.