# Ambientes

Simulador público, cuenta de prueba y producción, y cómo pasar de uno a otro.

Hay tres ambientes con el mismo contrato. Cambiar de ambiente es cambiar la base y la llave, sin tocar tu código.

| | Simulador público | Cuenta de prueba | Producción |
|---|---|---|---|
| Base | `https://widget.fital.xyz/explorar/v1` | `https://widget.fital.xyz/sandbox/v1` | `https://widget.fital.xyz/v1` |
| Cuenta | No hace falta | Panel y KYB aprobado, automático | Panel, KYB aprobado e inscripción de FITAL |
| Llave | Pública de prueba | `sk_test_fital_…`, por empresa | `sk_live_fital_…`, con login reciente |
| Dinero | Nunca | Nunca; saldos ficticios | Real |
| Estado entre llamadas | No guarda | Sí, por empresa | Real |
| Idempotencia | No real | Real | Real |
| Webhooks | [Script local](/docs/webhooks/inicio-rapido/) | Simulados y firmados | Reales |
| IP permitidas | No aplica | Opcional | **Obligatoria** |
| Firma de webhook | [Vector público](/docs/webhooks/verificar-firma/#vector-de-prueba) | Obligatoria | Obligatoria |
| `X-Fital-Scenario` | Sí | Sí | No aplica |
| Reinicio de datos | No hace falta | Sí, desde el panel | **No existe** |
| Rieles | Todos, sólo la forma | SPEI con CLABE `999`; otro riel da `403 rail_not_enabled` | Los habilitados a tu empresa |
| Límite de peticiones | 10 por segundo por IP | 5 por segundo por llave | Ver [Límites](/docs/limites/) |
| Tiempos | Inmediatos | Acortados | Reales de cada banco |
| Comisiones y tipos de cambio | Ejemplo | Ficticios | Reales |
| Revisiones y cumplimiento | No | Simulados por escenario, con tiempos ficticios | Reales; su duración no es predecible |

La cuenta de prueba es automática con KYB aprobado. Producción requiere además la inscripción de FITAL: sin ella, el panel responde `403 live_not_enabled` al crear una llave `sk_live_fital_…`. Las respuestas de ambos simuladores llevan `X-Fital-Environment: sandbox`, y las de la cuenta de prueba, `livemode: false` en su JSON.

## Qué no simula el simulador público

Estado entre llamadas, idempotencia real, saldos, tiempos, límites reales, comisiones, tipos de cambio, firmas ni KYB. Prueba la forma de tu integración, no su conducta. Para eso existe la cuenta de prueba.

Tres diferencias concretas. Una petición que no cumple el esquema, también si falta `Idempotency-Key` o es muy corta, responde `422` con `invalid_request` y sin señalar un campo, cuando la API real responde `400` con el detalle. Un escenario que no aplica a la operación responde `404` en formato `application/problem+json`. Y `request_id` del cuerpo de un error es fijo: el valor de cada petición viene en el encabezado `X-Request-Id`. Tu código de producción debe esperar siempre la forma de [Errores](/docs/errores/).

## Escenarios

Envía `X-Fital-Scenario: <nombre>` para elegir la respuesta.

| Escenario | Respuesta | Termina en | Enseña a manejar |
|---|---|---|---|
| `payment_completed` | 202 `processing` | Pago `completed` | Termina en `completed`. |
| `payment_failed` | 202 `processing` | Pago `failed` | El pago no se hizo y no queda dinero en tránsito. Si no ves `failed`, no repitas. |
| `payment_returned` | 202 `processing` | Pago `returned` | Devolución después de `completed`. |
| `insufficient_funds` | 422 `insufficient_funds` | No aplica | Saldo insuficiente. |
| `invalid_beneficiary` | 422 `invalid_beneficiary` | No aplica | Cuenta destino inválida. |
| `idempotency_key_reused` | 422 `idempotency_key_reused` | No aplica | Misma clave con otro cuerpo. |
| `pix_not_enabled` | 403 `not_enabled` | No aplica | PIX sin activación vigente para tu empresa. |
| `invalid_request` | 400 `invalid_request` | No aplica | Errores por campo en `details.fields`. |
| `invalid_api_key` | 401 `invalid_api_key` | No aplica | Llave mala o revocada. |
| `forbidden_scope` | 403 `forbidden_scope` | No aplica | Falta un scope. |
| `kyb_required` | 403 `kyb_required` | No aplica | Empresa sin aprobación. |
| `ip_not_allowed` | 403 `ip_not_allowed` | No aplica | IP fuera de la lista de la llave. |
| `not_found` | 404 `not_found` | No aplica | Recurso ajeno o inexistente. |
| `rate_limited` | 429 `rate_limited` | No aplica | Esperar lo que indique `Retry-After`. |
| `service_unavailable` | 503 `service_unavailable` | No aplica | Reintento con espera. |
| `status_degraded` | 200 | No aplica | Pausar sólo lo afectado. |

**Respuesta** es lo que devuelve la petición, y **Termina en** es el estado final del recurso. `No aplica` significa que la respuesta ya es el resultado. Un pago siempre nace en `202 processing`: el final no llega en esa respuesta. En el simulador público lo ves al consultar [`GET /v1/payments/{id}`](/docs/operaciones/consultar-pago/) con el mismo escenario. En la cuenta de prueba, el pago avanza solo hasta ahí y te llega por webhook.

Sin encabezado obtienes el camino feliz: `2xx`, y en un pago, `processing`.

Estos escenarios existen sólo en la cuenta de prueba:

| Escenario | Respuesta | Termina en | Enseña a manejar |
|---|---|---|---|
| `payment_in_review` | 202 `processing` | Pago `completed` | Revisión que termina en `completed`. |
| `payment_in_review_failed` | 202 `processing` | Pago `failed` | Revisión que termina en `failed`. El tiempo real de una revisión no es predecible. |
| `payment_held` | 422 `in_review` | No aplica | Sin `pay_`. Repite con la misma clave tras levantarse: crea un pago. |
| `payment_uncertain` | 202 `processing` | Pago `completed` | Resultado sin confirmar: la misma clave repite la respuesta y otra clave recibe `409 payment_in_flight`. |
| `account_restricted` | 403 `account_restricted` | No aplica | Cuenta restringida, sin `pay_`. |
| `collection_paid` | 201 `pending` | Cobro `paid` | Cobro que se paga, con su evento firmado. |
| `collection_expired` | 201 `pending` | Cobro `expired` | Cobro que vence, con su evento firmado. |
| `receiving_account_not_enabled` | 403 `not_enabled` | No aplica | Moneda sin activación para tu empresa. No abre nada. |
| `receiving_account_processing` | 202 `processing` | undefined `active` | Alta sin confirmar: no devuelve datos. Repite sin el escenario con la misma clave y se abre. |
| `deposit_received` | 201 `active` | Depósito `received` | Depósito con pagador ficticio, con su evento firmado. |

`collection_paid` y `collection_expired` se envían al crear el cobro, y `deposit_received` al crear la dirección de depósito. Lee el cobro con [`GET /sandbox/v1/collections/{id}`](/docs/operaciones/consultar-cobro/) y el depósito con [`GET /sandbox/v1/deposits`](/docs/operaciones/listar-depositos/); también llegan por webhook.

## Errores comunes

- `401 wrong_environment`: la llave no es de esa base. En el simulador público, `sk_test_fital_…` también recibe este error; su base es `https://widget.fital.xyz/sandbox/v1`.
- Confiar en un `200` del simulador público como prueba de que tu flujo funciona. Sólo prueba la forma.

## Qué sigue

[Cuenta de prueba](/docs/sandbox/cuenta-de-prueba/) y [Lista para producción](/docs/produccion/).
