Changelog

Novedades de la API

Cada cambio de la superficie pública queda registrado aquí, del más nuevo al más viejo. Son 159 entradas en 14 páginas; esta trae las más recientes. También puedes suscribirte al feed.

v3.35.0 Cambio

Errores que orientan e importación de contactos con lote vacío

Revisamos los errores que más recibieron las integraciones entre el 1 y el 9 de octubre. Varios eran un 500 donde correspondía un 400 o un 404, y otros decían qué estaba mal sin decir qué hacer. Ninguna respuesta exitosa cambia de forma.

POST /contacts/import acepta un lote vacío

  • contacts: [] ya no responde 400. Responde igual que una importación de cero filas: { "created": 0, "updated": 0, "skipped": 0, "errors": [] }, sin tocar nada. Sirve si partes tu archivo en lotes y a veces te sobra uno vacío.
  • El tope de 500 filas por lote no cambia.

Ids de ruta inválidos: 400 o 404, nunca 500

  • En flujos (/flows/{id}, /flows/{id}/run, /publish, /export, /nodes/{nodeId}/test, /flow-runs/{runId}) y automatizaciones (/automations/{id} y sus subrutas), un id que no es un UUID responde 400 invalid_id sin consultar nada. Pasa también con un segmento que no es un id: GET /workspaces/{workspaceId}/flows/runs y GET /workspaces/{workspaceId}/automations/templates no existen como rutas. Las ejecuciones de un flujo están en GET /flows/{id}/runs.
  • PUT /variables/{id} con un id que no existe en tu workspace responde 404 variable_not_found. PATCH /variables/field-definitions/{id} responde 404 field_definition_not_found.

403 endpoint_not_public dice qué usar

Cuando la ruta interna tiene un equivalente público, el mensaje lo nombra:

  • GET /auth/me y GET /workspaces/{id} → GET /me (identidad de la key y su workspace).
  • GET /channels/{channelId} → GET /channels/{channelId}/config.
  • GET /channels/{channelId}/whatsapp/phones → GET /channels/{channelId}/whatsapp/lines.
  • GET /workspaces/{workspaceId}/sandbox → POST /workspaces/{workspaceId}/runs para probar un Met.

El code sigue siendo endpoint_not_public; solo cambia el message.

send-template y display_phone_number

  • Si mandas display_phone_number a POST /channels/{channelId}/whatsapp/send-template, el 400 ahora te dice que la línea se elige con sender_line_id: el phone_number_id que devuelve GET /channels/{channelId}/whatsapp/lines.
v3.34.0 Nuevo

Líneas y plantillas editables, destinatarios de difusiones, equipo e historial de automatizaciones

Tercera entrega del reporte de brechas del SDK. Todo es aditivo, con dos scopes nuevos: channels:write y members:read. Ninguna key los tiene hasta que se los agregues.

Líneas de WhatsApp — PATCH /channels/{channelId}/whatsapp/lines/{lineId} (scope nuevo channels:write)

  • Cambia el alias de una línea y el flujo de entrada vinculado (flow_id, o null para quitarlo). lineId es el sender_line_id de GET /channels/{id}/whatsapp/lines.
  • Sin flujo propio, la línea usa el de su cuenta de WhatsApp y, si la cuenta no tiene, el del canal. La respuesta trae effective_flow_id y de dónde sale (effective_flow_source: line, account, channel o inactive).
  • El flujo tiene que ser de tu workspace, estar publicado y no estar archivado.
  • El Met de una línea lo decide el flujo vinculado (línea → flujo → nodo Met). Para que una línea no responda con un Met, vincúlale un flujo que no pase a uno.

Editar plantillas — PATCH /channels/{channelId}/templates/{templateId} (scope channels:manage)

  • Edita components y category de una plantilla existente sin cambiar su nombre, así no hay que tocar los flujos que la usan. name y language no se pueden cambiar.
  • La respuesta trae template_status, el estado de revisión que reporta Meta después de editar. Las reglas de cuándo se puede editar una plantilla aprobada las pone Meta; si rechaza el cambio, responde 400 template_edit_rejected con su mensaje.
  • Comparte el tope de cambios de plantillas con la creación.

Difusiones

  • GET /workspaces/{workspaceId}/broadcasts/{id}/recipients (scope channels:read): el estado de cada destinatario, paginado con limit / starting_after. Cada fila trae outcome (read, delivered, sent_unconfirmed, failed, no_message, pending, in_progress, not_sent), el acuse de WhatsApp aunque el flujo siga esperando, el error y el id del mensaje. Sin nombres ni teléfonos.
  • delivered_count en GET /broadcasts/{id}: destinatarios con acuse delivered o read, aunque su flujo siga esperando un botón. sent_count y failed_count cuentan flujos terminados, como siempre.
  • silenced_count en POST /broadcasts/preview-count: cuántos de esos destinatarios quedarían silenciados por piloto en pausa, apagado o porque pidieron un humano. A esos no se les envía nada.
  • Segmentos por plantilla recibida: { "field": "<nombre_plantilla>", "operator": "received_template", "value": "30" } (y not_received_template), con una ventana de 1 a 365 días. Los envíos fallidos no cuentan.
  • Los contactos con data.$subscribed = false ya se excluían de las difusiones; ahora está documentado.
  • Si el segmento no se puede calcular, no se envía nada: el preview responde 503 segment_unavailable y la difusión no se activa hasta el siguiente intento.

Equipo — GET /workspaces/{workspaceId}/team (scope nuevo members:read)

  • Las personas del workspace con id, name, email, role e is_active, paginadas con limit / starting_after. Incluye a las desactivadas. Nunca datos de acceso.

Eventos — GET /events

  • Filtros nuevos: contact_id, since (inclusivo) y until (exclusivo), en ISO 8601 con zona. Una fecha ambigua o un rango invertido responden 400 (invalid_date, invalid_date_range, invalid_contact_id).

Historial de automatizaciones — GET /workspaces/{workspaceId}/events

  • Crear, editar, activar, desactivar y borrar una automatización deja una entrada con entity_type: "automation" y acción created, updated, enabled, disabled o deleted: quién lo hizo (usuario o key, en metadata.api_key_id), qué campos cambiaron y el antes y el después. El id de la automatización va en metadata.automation_id.
v3.33.0 Nuevo

Plantillas paginadas, búsqueda por teléfono, desarchivar flujos y fechas con zona

Segunda entrega del reporte de brechas del SDK. Todo es aditivo: si ya integraste, nada se rompe.

Plantillas de WhatsApp — GET /channels/{channelId}/templates

  • page ahora pagina de verdad. Antes se ignoraba y cada página devolvía la lista completa. Con page (y limit de 1 a 200, 100 por defecto) las páginas van en un orden estable y la respuesta trae has_more. Sin page, la lista viene completa como siempre. Se leen hasta 500 plantillas por cuenta de WhatsApp: si una cuenta tiene más, las que pasan de ese tope no aparecen.
  • Cada plantilla trae quality_score (GREEN, YELLOW, RED o UNKNOWN) cuando Meta lo reporta. La calidad y el límite del número siguen en GET /channels/{id}/config (quality_rating, messaging_limit_tier).

Contactos — GET /contacts

  • phone: coincidencia exacta por teléfono normalizado. 3001234567, +57 300 123 4567 y 573001234567 encuentran al mismo contacto. Entre 6 y 15 dígitos; si no, 400 validation_error con param: "phone".
  • q ahora está documentado: busca en nombre, teléfono, correo e identidad. search se acepta como alias (antes se ignoraba); si llegan los dos, gana q.

Flujos

  • POST /workspaces/{workspaceId}/flows/{id}/unarchive saca un flujo del archivo y lo deja en borrador. No lo publica ni recrea sus disparadores: publícalo cuando quieras. Restaura el slug original si está libre; si no, responde slug_conflict: true y deja el slug renombrado.
  • Archivar libera el slug. El flujo archivado se renombra a <slug>--archivado-<id>, así que puedes crear otro con el mismo slug. La respuesta de DELETE /flows/{id} trae el slug nuevo. Los flujos que ya estaban archivados liberan su slug la primera vez que alguien intenta usarlo.
  • GET /workspaces/{workspaceId}/flows?include_archived=true incluye los archivados.
  • La salida fallback de los nodos que esperan un botón o una respuesta ahora está documentada: output_artifact.resolution es no_match si el contacto escribió otra cosa y timeout si se acabó la espera. Ver la guía de Funciones y flujos.

Fechas con zona horaria

  • created_at de mensajes, notas, búsqueda de mensajes, tool-calls y timeline de un contacto, y last_message_at de sus líneas, ahora salen en ISO 8601 con Z (antes, sin zona). Siempre fueron UTC: si ya las leías como UTC, no cambia nada.

Facturación — GET /billing/executions

  • limit está documentado: de 1 a 100, 50 por defecto. Un valor mayor se ajusta a 100 sin error, y la respuesta trae en limit el valor aplicado. Pagina con offset hasta total.

En los SDK: @meteor.ia/sdk 0.13.2 suma flows.unarchive, flows.list({ includeArchived }) y los tipos nuevos; meteor-ia 0.5.2 suma flows.unarchive y flows.list(include_archived=True).

v3.32.0 Cambio

Crear un contacto nunca devuelve a otra persona, y run acepta contact_id

POST /contacts ya no devuelve en silencio un contacto distinto del que pediste. Hasta hoy, si el canal ya tenía un contacto con la misma identidad, la API lo devolvía con el mismo 201 de una creación, aunque ese contacto tuviera otro teléfono: una carga masiva podía terminar actualizando y etiquetando a otra persona. Ahora:

  • La respuesta trae created. Si es false, ya existía un contacto con esa identidad en el canal y se devuelve sin cambiarlo (crear no es actualizar: para eso está PATCH /contacts/{id}), junto con matched_by ("user_ns").
  • Si esa identidad pertenece a un contacto con otro teléfono, responde 409 contact_identity_conflict y no crea ni devuelve nada. El message trae el id del contacto existente, nunca sus datos.
  • Si hay varios contactos con esa identidad, responde 409 contact_identity_ambiguous en lugar de crear un duplicado más.
  • El mismo número escrito de otra forma (con o sin indicativo, +52 1, +54 9) cuenta como el mismo: el 409 solo sale cuando los números son distintos.
  • Con name y sin first_name, ahora se llena el primer nombre ($first_name), así las plantillas que usan {{$contact.first_name}} no salen vacías.
  • El status sigue siendo 201 en los dos casos: ramifica por created.
{
  "success": true,
  "data": { "id": 161007, "data": { "$phone": "+573001234567" }, "created": false, "matched_by": "user_ns" }
}

POST /workspaces/{workspaceId}/flows/{id}/run acepta trigger_payload: { "contact_id": 123 } para correr un flujo sobre un contacto. Antes había que mandar { "kind": "contact", "payload": { "contact_id": 123 } }, y la forma corta se guardaba tal cual: los nodos de mensajería fallaban con «no hay contacto destinatario». La forma completa sigue igual. Con la forma corta:

  • Si el contacto no es de tu workspace: 404 contact_not_found, sin crear la ejecución.
  • Si contact_id no es un entero positivo: 400 invalid_contact_id.

Cambios de comportamiento en los flujos, sin cambio de contrato:

  • Publicar un flujo varias veces ya no suma disparadores. Cada publicación reemplaza los del flujo en lugar de crear otra automatización activa, que era lo que duplicaba mensajes. Una automatización creada a mano desde «Automatizaciones» no se toca.
  • Un nodo que falla corta su rama. Con on_error en stop (el valor por defecto), lo que sigue del nodo fallido ya no se ejecuta: queda omitido con el motivo upstream_failed. Las ramas paralelas no se afectan. Un nodo que une varias ramas se omite si cualquiera de ellas falló. Si tu flujo necesita seguir tras un fallo, pon ese nodo en on_error: "continue" o "branch".
  • contact.update toma el contacto del disparador cuando no le pasas contact_id, como ya hacían los nodos de WhatsApp.
  • Los saltos entre flujos (flow.goto) que nacen de una llamada por API, una automatización o una difusión ahora respetan el tope diario de automatizaciones.

En los SDK: @meteor.ia/sdk 0.13.2 tipa contacts.create como CreateContactResult (con created y matched_by) y documenta la forma corta de flows.run.

v3.31.0 Nuevo

El 402 energy_depleted dice dónde recargar (recharge_url)

Cuando el workspace se queda sin Energía, el 402 energy_depleted decía «recarga» pero no decía dónde. Y una key de workspace no tiene una operación para recargar, así que el siguiente paso quedaba sin enlace. Ahora el error trae un campo nuevo, error.recharge_url, con la página del panel de Met donde se recarga (Facturación), y el message la incluye:

{
  "success": false,
  "error": {
    "type": "invalid_request_error",
    "code": "energy_depleted",
    "message": "Sin Energía: recarga en Facturación (https://met.meteor.com.co/facturacion) para volver a ejecutar. Las lecturas y las operaciones que no consumen Energía siguen funcionando.",
    "recharge_url": "https://met.meteor.com.co/facturacion",
    "request_id": "req_01J8XYZ…"
  },
  "request_id": "req_01J8XYZ…"
}

Si ya manejas este error, no cambia nada. El estado (402), el type y el code son los mismos; solo se suma un campo y cambia el texto del message. Ramifica por code, nunca por el texto.

  • La página se abre con una sesión del workspace en el panel: es el enlace para pasarle a la persona que administra la cuenta, no una URL para llamar desde tu código.
  • Con una key de partner que porta workspaces:recharge, el message también nombra POST /workspaces/{workspaceId}/recharge, que carga Energía a una cuenta que tú aprovisionaste.
  • En los SDK llega como rechargeUrl (@meteor.ia/sdk 0.13.1) y recharge_url (meteor-ia 0.5.1) en el MetInvalidRequestError. Por el servidor MCP, la tool recibe recharge_url en el error, con la pista de pasarle el enlace a la persona.

Guía: Errores, idempotencia y paginación.

v3.30.0 Nuevo

Las listas que crecen solas se pueden recorrer enteras con paginate=true

Diecisiete listas que crecen con el uso diario —tareas, actividad, comentarios, conversaciones, mensajes, difusiones, notas, archivos, vínculos, recordatorios, facturas— se cortaban en un tope fijo y no había forma de pedir lo que seguía. Ahora sí.

Si ya las usas, no cambia nada. Sin parámetros nuevos, cada endpoint responde exactamente lo mismo que ayer: el mismo array (o el mismo objeto), el mismo tope y el mismo orden.

Para recorrerlas enteras, agrega paginate=true. La respuesta llega como { data, has_more, next_cursor }. Para la página siguiente, manda next_cursor tal cual en starting_after, hasta que has_more sea false:

curl "https://api.met.meteor.com.co/api/v1/contacts/42/notes?paginate=true&limit=50" \
  -H "Authorization: Bearer $MET_API_KEY"
# → { "data": [...50 notas], "has_more": true, "next_cursor": "eyJvIjo1MH0" }

curl "https://api.met.meteor.com.co/api/v1/contacts/42/notes?paginate=true&limit=50&starting_after=eyJvIjo1MH0" \
  -H "Authorization: Bearer $MET_API_KEY"
# → { "data": [...], "has_more": false, "next_cursor": null }
  • limit va de 1 a 100; sin él son 20, igual que en /events y /runs.
  • El cursor es opaco: úsalo tal cual llegó. Uno que no se entiende responde 400 validation_error con param: "starting_after".
  • Mandar starting_after también te da la forma nueva, aunque no pongas paginate. La excepción es GET /billing/invoices: ahí starting_after ya existía con el id de Stripe y devolvía el array, así que sin paginate=true lo sigue haciendo.
  • No hay total: contar todo en cada página no escala y miente cuando los datos cambian.
  • page sigue funcionando en la forma de siempre; en la nueva se avanza con el cursor.

Endpoints

En la forma nueva
GET/workspaces/{workspaceId}/tasks
GET/workspaces/{workspaceId}/tasks-activity
GET/tasks/{taskId}/activity
GET/tasks/{taskId}/comments
GET/tasks/{taskId}/linked-items
GET/workspaces/{workspaceId}/conversationsordenadas por id, de la más nueva a la más vieja
GET/workspaces/{workspaceId}/conversations/{convId}/messagesconserva messages y threads y suma data, has_more y next_cursor
GET/workspaces/{workspaceId}/broadcastscada plantilla trae todas sus corridas en runs
GET/contacts/{contactId}/notes
GET/contacts/{contactId}/messages/search
GET/contacts/{id}/duplicatesconserva data y suma has_more y next_cursor; ordenados por id y sin el tope de 50 por criterio
GET/items/{itemId}/comments
GET/items/{itemId}/files
GET/items/{itemId}/links
GET/items/{itemId}/activity
GET/reminders
GET/billing/invoicessolo paginate=true activa la forma nueva; next_cursor es el id de Stripe de la última factura

En las conversaciones, sus mensajes, los duplicados y las facturas el cursor avanza por id, así que un registro nuevo no corre las páginas. En las demás avanza por desplazamiento: si algo entra o sale mientras recorres, una fila puede repetirse o faltar.

En los SDK

@meteor.ia/sdk 0.13.1 y meteor-ia 0.5.1 traen un iterador por lista (met.tasks.iterate(), met.contacts.iterateNotes(42), met.conversations.iterateMessages(42), met.billing.iterateInvoices()…) que hace todo esto por ti. Los métodos de siempre no cambian.

Más detalle en Errores, idempotencia y paginación.

v3.29.0 Cambio

El contrato declara las cabeceras de límite — y el rate limit es por operación

La API ya mandaba en cada respuesta X-RateLimit-Limit, X-RateLimit-Remaining y X-RateLimit-Reset, y Retry-After en el 429. Desde ahora el contrato OpenAPI también las declara, en las 2xx de cada operación y en el 429. Si generas tu cliente del spec, ahora las ve. Las cabeceras del tope diario (X-Daily-Limit, X-Daily-Remaining y X-Daily-Reset) quedan declaradas igual; solo salen si tu plan tiene tope diario.

Una precisión que la guía decía mal. El rate limit por minuto se cuenta por key y por operación, no uno solo para toda la key: cada endpoint lleva su propio contador. Si tu key lista contactos a todo ritmo, no se queda sin cupo para crear runs. X-RateLimit-Remaining te dice cuánto le queda a esa operación, no a la key entera. El comportamiento no cambió; lo que cambió es que ahora está documentado como es.

Nada que tengas que hacer. Los detalles están en Límites.

v3.28.0 Cambio

GET /me ya no pide scope, y las imágenes tienen el suyo (images:generate)

Dos cambios de scopes. Ninguno le quita nada a una key que ya existe.

GET /me responde a cualquier key válida. Ahora pide identity:read, un scope que toda key tiene sin marcarlo. Hasta hoy pedía runs:read, y una key sin ese scope recibía 403 justo en la llamada que sirve para averiguar qué le falta. Las demás validaciones no cambian: la key tiene que estar activa y tu plan tiene que incluir la API. met whoami y met.me.retrieve() funcionan igual.

Generar imágenes y video pide images:generate. POST /workspaces/{workspaceId}/images/generate, /edit y /video colgaban de integrations:execute, el mismo scope que ejecutar tools de tus integraciones: quien quería una cosa tenía que dar la otra. Ahora son dos permisos separados.

  • Si tu key ya tenía integrations:execute, ya tiene images:generate. Se lo agregamos antes de este cambio, así que tu integración sigue igual.
  • Una key nueva que genere imágenes tiene que marcar images:generate al crearla. integrations:execute ya no alcanza.
  • Igual que antes, una key de test (met_test_…) recibe 403 test_mode_restricted: generar llama a un proveedor de pago y debita Energía.

La tabla completa de scopes está en Autenticación.

v3.27.0 Cambio

Once operaciones quedan deprecadas y dejan de responder el 8 de abril de 2027

Once operaciones de la API quedan deprecadas y dejan de responder el 8 de abril de 2027. Hasta esa fecha funcionan igual que hoy. Desde ya, cada respuesta trae las cabeceras Deprecation, Sunset y Link, para que te enteres aunque no leas este changelog.

Tienen un reemplazo que ya existe. Cambia la llamada cuando toques ese código:

DeprecadaUsa en su lugarPor qué
GET /workspaces/{workspaceId}/activityGET /workspaces/{workspaceId}/eventsDevuelven exactamente lo mismo.
POST /workspaces/{workspaceId}/itemsPOST /collections/{collectionId}/itemsExige collection_id igual que la otra: un ítem no existe fuera de una colección.
PATCH /collections/{collectionId}/items/{id}/fieldPATCH /collections/{collectionId}/items/{id} con data: { campo: valor }Hace lo mismo y además te deja tocar varios campos a la vez.
DELETE /contactsDELETE /contacts/bulk con la lista de idsBorraba todos los contactos del workspace sin confirmación. Con la lista explícita, un slash de más no te vacía la base.
POST /workspaces/{workspaceId}/skills/{skillId}/testPOST /workspaces/{workspaceId}/runs con un Met que tenga la habilidadNo ejecutaba la habilidad: devolvía un texto de relleno. Un run sí la ejecuta.

No tienen reemplazo, porque no son datos del workspace: son el orden del menú del panel de Met. Si las usas, tu integración no pierde nada al dejarlas.

  • PUT /collections/{id}/pin
  • PATCH /collections/{collectionId}/views/reorder
  • POST /workspaces/{workspaceId}/folders/reorder
  • POST /folders/{folderId}/collections/reorder
  • POST /workspaces/{workspaceId}/collections/reorder
  • PATCH /workspaces/{workspaceId}/task-views/reorder

El orden de los pasos de una tarea y de los bloques de un ítem no se deprecan: eso sí es contenido.

En los SDK, los métodos correspondientes quedan marcados como deprecados en la próxima versión. La política está en Versionado y deprecación.

v3.26.0 Nuevo

Lee y edita Mi negocio por API, con scopes propios

Dos rutas nuevas para los ajustes de Mi negocio de tu workspace, con dos scopes nuevos:

  • GET /workspaces/{workspaceId}/business (scope business:read) devuelve name, description, logo_url, business_prompt, su largo en business_prompt_chars y el tope en business_prompt_max (8000 caracteres).
  • PATCH /workspaces/{workspaceId}/business (scope business:write) cambia description, business_prompt o los dos, y devuelve lo mismo que el GET.

El prompt del negocio es el texto que se inyecta en el system prompt de todos los Mets del workspace, así que un cambio lo leen todos en su próximo turno. El PATCH reemplaza el prompt entero: si quieres sumarle algo, léelo primero, edítalo y mándalo completo. Si pasa del tope responde 400 y no guarda nada; un cuerpo sin ninguno de los dos campos responde 400 business_empty_update. Para vaciar un campo manda ""; null no se acepta.

Hasta hoy esto solo se podía hacer llamando las tools meteor_get_business_info y meteor_update_business_prompt por POST /integrations/{id}/tools/{tool}. Esa vía sigue funcionando; la ruta nueva no necesita la integración y tiene su propio permiso, así que puedes dar una key que lea Mi negocio sin darle acceso a ejecutar herramientas.

Lo que no trae. Los campos del negocio (horario, teléfono, moneda…) son variables del workspace y se leen con GET /variables (scope variables:read). El nombre y el logo se cambian desde el panel. Ninguna de las dos rutas devuelve secretos. El catálogo de tipos de nodo de los flujos ya era público: está en GET /node-registry (scope automations:read).

En el SDK de TypeScript es met.business.retrieve() y met.business.update({ business_prompt }); en Python, met.business.retrieve() y met.business.update(business_prompt=...). El workspaceId tiene que ser el de tu key: con el de otro workspace la petición se rechaza sin leer ni escribir nada.

v3.25.0 Cambio

El evento task.completed queda deprecado — no se emite desde el 31 de agosto

El evento de webhook task.completed queda deprecado y se retira del catálogo el 7 de abril de 2027.

Ya no se emite. Lo disparaba la ejecución de tareas agénticas, que se retiró el 31 de agosto de 2026 (versión 3.0.0): desde entonces una tarea es un checklist de personas y no hay corrida que termine. Si tienes un endpoint suscrito a task.completed, no recibió nada desde esa fecha y no va a recibir nada.

Qué no cambia hasta el retiro. task.completed sigue siendo un valor válido de enabled_events: crear o editar un endpoint que lo incluye no falla, y GET /webhook-endpoints/event-types lo sigue listando, ahora con su descripción marcada como deprecada. Así ninguna integración que lo tenga en su lista se rompe antes de la fecha.

Qué hacer. Sácalo de enabled_events cuando toques tu endpoint. Si lo usabas para enterarte de que terminó un procedimiento, ese trabajo ahora lo hacen los flujos: escucha automation.run.failed para enterarte de los que fallan, o haz que el propio flujo te avise con un nodo de petición HTTP.

El 7 de abril de 2027 task.completed sale del catálogo y del enum de enabled_events. La política de deprecación está en Versionado y deprecación.

v3.24.0 Nuevo

Las facturas traen lo reembolsado y sus notas crédito

Cada factura de GET /billing/invoices trae dos campos opcionales nuevos:

  • amount_refunded: lo devuelto de esa factura, en la moneda de currency y en unidad mayor, igual que amount_paid. Suma lo de sus notas crédito, en dinero o acreditadas al saldo, y, si no tiene ninguna, lo reembolsado directamente sobre el pago. 0 quiere decir que no se devolvió nada.
  • credit_notes: las notas crédito de la factura (sin las anuladas, con las acreditadas al saldo), cada una con number, amount, pdf_url y created. pdf_url es un enlace temporal, como invoice_pdf.

En una cuenta gestionada por un partner no llega ninguno de los dos, por la misma razón por la que number e invoice_pdf llegan en null: son documentos a nombre del partner. En una cuenta que no es gestionada, cualquiera de los dos puede faltar cuando no se pudo saber en ese momento: la consulta no alcanzó a responder, o el pago es más viejo que lo que se consulta. Un campo ausente no quiere decir 0 ni que no haya notas.

El cambio es aditivo: el resto de la respuesta no cambia.