# SDK de Ruby

Instala la gema fiscalrail y utiliza su cliente de API, modelos de respuesta y helpers fiscales.

La gema oficial [`fiscalrail`](https://rubygems.org/gems/fiscalrail) cubre las 42 operaciones de la [referencia de la API](/en/api/introduction). La versión `0.4.0` requiere Ruby 3.3 o posterior y funciona con o sin Rails. El [código fuente y las versiones](https://github.com/fiscalrail/fiscalrail-ruby) están disponibles en GitHub.

## Instala y autentica

Añade la gema a tu `Gemfile` y ejecuta `bundle install`:

```ruby
gem "fiscalrail", "~> 0.4.0"
```

Crea un cliente con una clave de API explícita:

```ruby
require "fiscalrail"

client = FiscalRail::Client.new(api_key: ENV.fetch("FISCALRAIL_API_KEY"))
```

Tu aplicación lee la clave desde su entorno o gestor de secretos; el SDK no la busca automáticamente. Test y Live usan la misma URL base. La clave selecciona el entorno de la cuenta.

Reutiliza el cliente durante la vida del proceso y llama a `client.close` al cerrarlo. El adaptador HTTP mantiene una conexión y ejecuta las peticiones concurrentes de forma secuencial. Usa clientes separados si necesitas peticiones HTTP en paralelo. `FiscalRail::Client.open(api_key: key) { |client| ... }` cierra la conexión al terminar el bloque. Tu aplicación conserva la responsabilidad de cerrar los adaptadores que inyecte mediante `adapter:`.

## Emite una factura

Usa `BigDecimal` o cadenas para los importes y los helpers de España para los impuestos del catálogo:

```ruby
require "fiscalrail"

client = FiscalRail::Client.new(api_key: ENV.fetch("FISCALRAIL_API_KEY"))

invoice = client.invoices.issue(
  idempotency_key: "2f294ef2-9a60-4c7e-a573-5e18fa8348e2",
  lines: [{ description: "Consulting", quantity: 2, unit_price: BigDecimal("75.00"),
            taxes: [FiscalRail::TaxRegimes::ES::VAT.general] }]
)
```

Las peticiones aceptan argumentos con nombre y hashes anidados con claves de tipo símbolo o cadena. Los campos omitidos no se envían; `nil`, `false` y los arrays vacíos se conservan cuando se indican explícitamente. Las fechas y horas se serializan como cadenas ISO 8601. La API valida las reglas de negocio.

## Modelos de respuesta

Las respuestas son objetos generados de solo lectura bajo `FiscalRail::Models`. Las fechas se convierten en `Date`, las marcas de tiempo en `Time` y los decimales en `BigDecimal`:

```ruby
invoice.id
invoice.issue_date
invoice.totals.payable
invoice.request_id
invoice.idempotency_key
invoice.idempotent_replayed
invoice.to_h
```

Los valores anidados están congelados. Los campos desconocidos siguen disponibles en `extra_fields` y `response["field"]`; `to_h` devuelve contenedores nuevos con claves de cadena. Una estructura de respuesta inválida genera `FiscalRail::ResponseParseError` con la ruta del campo y el identificador de la petición.

## Idempotencia y reintentos

`issue` y `amend` generan una clave de idempotencia si no proporcionas una. Los reintentos de esa llamada la reutilizan. Para trabajos persistentes, guarda tu propia `idempotency_key:` antes del primer intento y pásala en cada reintento, incluso tras reiniciar el proceso. Una llamada nueva sin clave genera otra distinta. Nunca reutilices una clave para otra operación o contenido.

Por defecto se realizan como máximo dos reintentos ante fallos de conexión, tiempos de espera agotados y respuestas HTTP `408`, `429` o `5xx`, solo para operaciones seguras: lecturas, emisiones y rectificaciones con idempotencia, generación de PDF y activación o desactivación de destinos. Las llamadas ordinarias de creación, actualización y eliminación no se reintentan automáticamente. El cliente respeta `Retry-After`, limitado a 30 segundos, y en su ausencia usa espera exponencial. Configura `max_retries: 0` para desactivar los reintentos.

## Errores

Todos los errores del SDK heredan de `FiscalRail::Error`. Los errores de API incluyen `status_code`, `code`, `request_id`, `details` e `idempotency_key`:

```ruby
begin
  invoice = client.invoices.retrieve("inv_...")
rescue FiscalRail::APIConnectionError => error
  warn error.message
rescue FiscalRail::APIError => error
  warn "#{error.code}: HTTP #{error.status_code}, request #{error.request_id}"
end
```

Los errores de conexión y tiempo de espera también conservan la clave de idempotencia. Guárdala cuando no sepas si una emisión o rectificación llegó a completarse.

## Recursos disponibles

El cliente expone `account`, `account_tax_regimes`, `balances`, `api_keys`, `customers`, `event_destinations`, `events`, `invoice_series`, `payment_instructions`, `invoices`, `invoice_pdfs`, `tax_ids` y `tax_regimes`. Cada operación de la referencia incluye un ejemplo en Ruby. Las facturas usan `issue` y `amend`; las facturas emitidas nunca se actualizan.

Las rutas de cuenta singleton requieren una versión del SDK generada a partir del contrato OpenAPI actual. Las versiones publicadas todavía usan IDs de cuenta.

Consulta el estado de una cuenta con `client.balances.retrieve()` y `client.account_tax_regimes.retrieve()`. El recurso independiente `tax_regimes` describe el catálogo público.

## Paginación

`list` obtiene una página. Usa `auto_paging_each` para recuperar las siguientes a medida que las recorres, conservando los filtros:

```ruby
page = client.customers.list(country: "ES", limit: 25)
page.each { |customer| puts customer.name }

client.invoices.auto_paging_each(customer: "cus_...", page_size: 100) do |invoice|
  puts invoice.code
end
```

Las páginas exponen `data` y `has_more`. Para gestionar los cursores manualmente, pasa `starting_after:` o `ending_before:` a `list`. Las cuentas y los regímenes fiscales devuelven listas únicas y no ofrecen paginación automática.

## PDF de facturas

`render` y `retrieve` devuelven metadatos del PDF, incluida una URL para el cliente. Para descargar directamente los bytes:

```ruby
client.invoice_pdfs.render_content(invoice.id, locale: "es").write_to_file("invoice.pdf")
```

Los métodos `_content` devuelven `FiscalRail::BinaryContent`. Las descargas se almacenan en memoria. `locale:` se convierte en la cabecera `Accept-Language`.

## Verifica webhooks

Verifica el cuerpo sin modificar antes de procesar el evento. En un controlador de Rails:

```ruby
event = FiscalRail::Webhooks.construct_event(
  request.raw_post,
  request.headers["FiscalRail-Signature"],
  signing_secret
)
```

El helper verifica el HMAC en tiempo constante, rechaza marcas de tiempo que se alejen más de cinco minutos en cualquier dirección e interpreta el evento como un hash con claves de cadena. Si la verificación falla, genera `FiscalRail::WebhookSignatureError`. Consulta [webhooks](/es/webhooks) para conocer el comportamiento de entrega y confirmación.
