# Idempotencia, errores y límites

Cómo reintentar las mutaciones de Invoise de forma segura, qué significan los códigos de error y qué límites se aplican.

Source: https://docs.invoise.me/es/integration/idempotency-and-errors/

Si una solicitud agota el tiempo de espera, no sabes si tuvo éxito. Reintenta la misma operación con la misma `Idempotency-Key` para evitar crear un segundo pago.

## Una clave por acción

1. Genera una clave única antes de la primera solicitud y guárdala con tu pedido.
2. Envíala en `Idempotency-Key` al crear o cambiar un recurso de negocio.
3. Tras un tiempo de espera agotado, reintenta el mismo método, ruta y cuerpo con esa clave.
4. Para una acción nueva, crea una clave nueva.

La clave debe ser no vacía y de como máximo 128 bytes. Repetir una acción completada devuelve su respuesta guardada. Cambiar el cuerpo con la misma clave devuelve `409 idempotency_conflict`.

Esto se aplica a mutaciones de negocio como facturas, tiendas, claves y webhooks. Las llamadas GET de solo lectura y los retos de inicio de sesión no usan este mecanismo. Sigue los requisitos de cada endpoint.

`external_id` ayuda a asociar un pago con tu pedido; no es una clave de idempotencia.

## Consulta errores por código

Ejemplo:

```json
{"error":{"code":"idempotency_conflict","message":"idempotency_conflict"}}
```

Usa `error.code` en tu programa. No infieras el éxito a partir del cuerpo de la respuesta sin comprobar antes el estado HTTP.

| Código | Próxima acción |
| --- | --- |
| `unauthorized` | Comprueba la credencial, los permisos y cualquier restricción de IP. Inicia sesión de nuevo si la sesión caducó. |
| `mfa_required` | Completa el segundo factor de la cuenta usando su sesión. |
| `onboarding_required` | Completa `/onboarding` antes de las operaciones de tienda. |
| `idempotency_key_required` | Proporciona una clave guardada no vacía, de como máximo 128 bytes. |
| `idempotency_conflict` | Localiza la solicitud original. No crees un nuevo pago en silencio. |
| `json_content_type_required` / `invalid_json` | Envía `Content-Type: application/json` y solo campos documentados. |
| `unsupported_network` / `unsupported_asset` | Elige una red y un token compatibles. |
| `network_not_ready` / `asset_not_ready` | Espera a que esté disponible o elige otra ruta lista. |
| `amount_below_minimum` / `fee_exceeds_amount` | Comprueba el importe, los decimales y las condiciones de la tienda. |
| `shop_archived` / `shop_not_found` | Comprueba la tienda y el acceso. |
| `invalid_expires_in` | Envía `1d`, `7d`, `30d`, `180d` o `365d`, y solo al crear una factura. Los depósitos no caducan. |
| `invalid_assets` / `issuance_in_group` | Envía pares `{chain_id, token}` distintos sin `chain_id` ni `token`; cancela o pausa un grupo mediante su propio `id`. Consulta [varios tokens o redes](https://docs.invoise.me/es/payments/deposits-and-invoices/#ofrece-varios-tokens-o-redes). |
| `solana_setup_required` / `tron_setup_required` | Configura antes el [destinatario de Solana o Tron](https://docs.invoise.me/es/payments/solana-and-tron/) de la tienda. |
| `invoice_amount_limit` / `sandbox_amount_limit` | Reduce el importe hasta el [límite](#límites). |
| `active_invoice_limit_reached` / `deposit_address_limit_reached` | Cancela facturas o deshabilita depósitos que ya no necesites, o pídele a Invoise que aumente el límite. |
| `api_key_limit_reached` / `too_many_allowed_ips` / `webhook_limit_reached` | Revoca claves sin usar, acorta la lista de IP o reutiliza un endpoint existente. |
| `team_limit_reached` | Elimina a un miembro o revoca una invitación pendiente, o pídele a Invoise que aumente el límite. |
| `account_disabled` | El personal de Invoise bloqueó la cuenta; el motivo está en `error.details`. Consulta [cuentas bloqueadas](https://docs.invoise.me/es/integration/team-and-access/#cuentas-bloqueadas). |
| `rate_limited` | Espera el número de segundos indicado en `Retry-After` antes de reintentar. |

## Límites

Cuando una solicitud superaría un límite, Invoise la rechaza con el cuerpo de error habitual y el código de abajo.

| Límite | Valor | Error |
| --- | --- | --- |
| Importe de una factura | 1,000,000 tokens | `400 invoice_amount_limit` |
| Importe de una factura sandbox o transferencia simulada | 10,000 tokens | `400 sandbox_amount_limit` |
| Facturas activas por comercio | 2,000 | `400 active_invoice_limit_reached` |
| Direcciones de depósito activas por comercio, por familia de red | EVM 10,000, Tron 10,000, Solana 10 | `400 deposit_address_limit_reached` |
| Claves de API por tienda no revocadas | 10 | `400 api_key_limit_reached` |
| Direcciones IP o rangos CIDR permitidos por clave | 10 | `400 too_many_allowed_ips` |
| Endpoints de webhook por tienda | 10 | `400 webhook_limit_reached` |
| Miembros del equipo e invitaciones pendientes por comercio | 10 | `400 team_limit_reached` |
| Solicitudes por minuto | 1,200, de las cuales como máximo 120 no son GET | `429 rate_limited` |

Los límites de importe están en tokens enteros, no en unidades base. Todos los tokens compatibles son stablecoins de dólar, así que 1,000,000 tokens equivale aproximadamente a $1,000,000.

Una factura está activa hasta que se paga, se cancela o caduca. Una factura ofrecida en varias redes cuenta una sola vez. Una dirección de depósito está activa hasta que se deshabilita; cada opción de red de un depósito es una dirección independiente. Sandbox y producción se cuentan por separado para ambos límites. El personal de Invoise puede cambiar los límites de facturas, direcciones de depósito y equipo de un comercio.

El límite de equipo se aplica tanto al invitar como al aceptar una invitación. La URL de un endpoint de webhook se puede cambiar, así que puedes reutilizar un endpoint en lugar de añadir uno nuevo.

Las solicitudes se cuentan por clave de API, por sesión del panel, o por IP del cliente cuando no está autenticado. Una respuesta `429` incluye `Retry-After: 60`.

## Reintenta sin duplicados

Reintenta los tiempos de espera agotados y los errores temporales del servidor con la **misma clave**, usando retrasos crecientes. Ante un `429`, espera los segundos indicados en `Retry-After`; no envíes más solicitudes de inmediato. Corrige los errores de entrada inválida y de acceso antes de reintentar.

Para los webhooks, Invoise reintenta la entrega. Acepta el evento de forma duradera, devuelve 2xx y luego procésalo. Evita duplicados usando `Invoise-Event-ID`.

Las rutas antiguas `/projects` son alias de `/shops`, incluido su alcance de idempotencia. Usa `/shops` para las integraciones nuevas. Los nombres de error heredados pueden usar `project_*`.
