> For the complete documentation index, see [llms.txt](https://docs.realcity.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.realcity.dev/script-docs/rc-billing/integracion.md).

# Integración

## Integración y API

Esta página documenta la superficie pública soportada para conectar otros recursos con RC Billing. Los callbacks NUI y los eventos internos pueden cambiar entre versiones; no deben utilizarse como API externa.

### Export de servidor `CreateInvoice`

Nombre completo:

```lua
exports['rc-billing']:CreateInvoice(data)
```

La llamada es síncrona y debe hacerse desde código de servidor. Devuelve una tabla con `success`, un mensaje y, cuando se crea correctamente, `invoiceId`.

### Campos de entrada

| Campo                 | Tipo     | Obligatorio | Descripción                                   |
| --------------------- | -------- | ----------- | --------------------------------------------- |
| `creatorSource`       | `number` | Sí          | Server ID conectado del personaje emisor.     |
| `recipientSource`     | `number` | Condicional | Server ID conectado del destinatario.         |
| `recipientIdentifier` | `string` | Condicional | Identificador persistente del destinatario.   |
| `recipientDNI`        | `string` | Condicional | Alias de `recipientIdentifier`.               |
| `recipientName`       | `string` | Condicional | Nombre cuando no se usa `recipientSource`.    |
| `amount`              | `number` | Sí          | Importe positivo, sujeto a límites.           |
| `description`         | `string` | Sí          | Entre 3 y 255 caracteres.                     |
| `category`            | `string` | No          | ID de categoría; predeterminado `service`.    |
| `source`              | `string` | No          | `personal` o trabajo del emisor.              |
| `dueDays`             | `number` | No          | Días hasta vencimiento.                       |
| `resource`            | `string` | No          | Nombre del recurso originador para auditoría. |

Debes proporcionar una de estas parejas:

* `recipientSource`, mientras el destinatario está conectado.
* `recipientIdentifier` y `recipientName` para un destinatario persistente.
* `recipientDNI` y `recipientName` como alias del caso anterior.

Cuando existe `recipientSource`, el servidor obtiene identificador y nombre desde el framework e ignora valores de identidad aportados por el llamador.

### Respuesta

#### Correcta

```lua
{
    success = true,
    invoiceId = 1842,
    message = 'Factura #1842 creada correctamente.'
}
```

#### Fallida

```lua
{
    success = false,
    message = 'Descripción demasiado corta.'
}
```

No dependas del texto de `message` para lógica. Está localizado. Usa `success` y registra el mensaje para diagnóstico.

### Ejemplo personal

```lua
RegisterNetEvent('my-resource:server:billPlayer', function(targetSource, amount, reason)
    local src = source

    local result = exports['rc-billing']:CreateInvoice({
        creatorSource = src,
        recipientSource = tonumber(targetSource),
        amount = tonumber(amount),
        description = tostring(reason),
        category = 'service',
        source = 'personal',
        dueDays = 7,
        resource = GetCurrentResourceName()
    })

    if not result.success then
        print(('[my-resource] Invoice failed for source %s: %s'):format(src, result.message))
        return
    end

    print(('[my-resource] Created invoice #%s'):format(result.invoiceId))
end)
```

El export vuelve a comprobar `Config.AllowPersonalInvoices` y ACE. No permite saltarse la política del recurso.

### Ejemplo de empresa

```lua
local result = exports['rc-billing']:CreateInvoice({
    creatorSource = source,
    recipientSource = customerSource,
    amount = 3200,
    description = 'Reparación completa del motor',
    category = 'repair',
    source = 'mechanic',
    dueDays = 3,
    resource = GetCurrentResourceName()
})
```

El trabajo actual del emisor debe coincidir con `source`, estar en `Config.CompanyJobs` y alcanzar `minRank`. El export calcula comisión y sociedad desde la configuración; el recurso integrador no debe calcularlas.

### Ejemplo con destinatario desconectado

```lua
local result = exports['rc-billing']:CreateInvoice({
    creatorSource = source,
    recipientIdentifier = citizenId,
    recipientName = characterName,
    amount = 500,
    description = 'Tasa administrativa',
    category = 'tax',
    source = 'personal',
    resource = GetCurrentResourceName()
})
```

El export guarda la factura, pero no puede abrir el aviso interactivo a un jugador desconectado. El receptor la verá en su historial y recibirá un recordatorio al conectarse.

La factura se crea como `awaiting_acceptance`. El destinatario debe aceptarla para que pase a `pending` y pueda pagarse.

### Recomendaciones de seguridad

No conectes directamente un evento de cliente al export sin validar el contexto de tu propio recurso. Aunque RC Billing valida permisos e importes, tu integración debe decidir cuándo una acción de gameplay autoriza facturar.

Evita este patrón:

```lua
-- No recomendado: el cliente controla todos los datos sin contexto de gameplay.
RegisterNetEvent('my-resource:bill', function(data)
    exports['rc-billing']:CreateInvoice(data)
end)
```

Prefiere construir el payload en servidor usando datos confiables:

```lua
RegisterNetEvent('mechanic:server:finishRepair', function(orderId, customerSource)
    local src = source
    local order = ActiveRepairOrders[orderId]
    if not order or order.mechanicSource ~= src then return end

    exports['rc-billing']:CreateInvoice({
        creatorSource = src,
        recipientSource = customerSource,
        amount = order.serverCalculatedPrice,
        description = order.invoiceDescription,
        category = 'repair',
        source = 'mechanic',
        resource = GetCurrentResourceName()
    })
end)
```

### Compatibilidad de versiones

La API pública estable de la versión actual contiene únicamente `CreateInvoice`. Si una versión futura añade exports, quedarán registrados aquí y en `CHANGELOG.md`.

Para detectar fallos sin acoplarte al idioma:

```lua
local ok, result = pcall(function()
    return exports['rc-billing']:CreateInvoice(payload)
end)

if not ok then
    print(('[integration] rc-billing export unavailable: %s'):format(result))
elseif not result.success then
    print(('[integration] rc-billing rejected invoice: %s'):format(result.message))
end
```

Comprueba que `GetResourceState('rc-billing') == 'started'` si tu integración puede arrancar antes que este recurso.
