# SDK de servidor PHP y Laravel

URL: https://traqio.app/es/docs/sdks/php
Last updated: 2026-10-16

Reporta registros y compras desde un backend PHP o Laravel con traqio/traqio-php y vincula cada uno a su clic. Descubrimiento automático en Laravel.

`traqio/traqio-php` es el SDK de Traqio para backends PHP y Laravel — la mitad servidor del SDK web de Traqio. La conversión que cuenta en un sitio web — un registro, una suscripción, una compra — ocurre en tu backend, donde se conoce el id de usuario. Este paquete la reporta con el **trackID**, el click id del anuncio que [@traqio/web](https://traqio.app/es/docs/sdks/web) guardó en almacenamiento first-party desde la página de llegada, y Traqio acredita la campaña que trajo al usuario — [de forma determinista](https://traqio.app/es/docs/concepts/web-attribution), por el id de ese clic. Sin más dependencia que `ext-curl`; descubrimiento automático en Laravel.

## Requisitos

- PHP 8.1 o posterior, con `ext-curl` y `ext-json`. Laravel 12 o 13 para la integración con descubrimiento automático; si no, PHP simple, Symfony o cualquier framework PSR-7.
- Una **clave de servidor** para el producto (`tq_sk_…`). Ni la clave SDK de la app ni una clave web funcionan aquí.
- [@traqio/web](https://traqio.app/es/docs/sdks/web) en el sitio, y anuncios que apunten a [enlaces de seguimiento](https://traqio.app/es/docs/concepts/tracking-links) con un destino web — así es como el trackID llega a tu formulario de registro.

## Configuración

### Crear una clave de servidor

En la consola, abre **Integraciones → SDK** y crea una **clave de servidor**. Se muestra una sola vez: ponla en `.env`, nunca en el código ni en una página. Traqio solo guarda su huella; una clave perdida se sustituye por una nueva y la antigua se revoca.

.env:
```bash
TRAQIO_SECRET_KEY=tq_sk_...
```

### Instalar el paquete

```bash
composer require traqio/traqio-php
```

Mientras el paquete no esté en Packagist, añade la carpeta que te enviamos como repositorio de tipo path:

```bash
# the folder you received, committed inside the backend's repository
composer config repositories.traqio path ./vendor-src/traqio-php
composer require traqio/traqio-php:@dev
```

### Configurar el cliente

**Laravel**: no hay nada que escribir — el service provider y la facade `Traqio` se descubren solos y leen `TRAQIO_SECRET_KEY`. Para cambiar el endpoint, el timeout o los reintentos, publica el archivo de configuración:

```bash
php artisan vendor:publish --tag=traqio-config
```

**PHP simple**: un cliente, creado una vez.

```php
use Traqio\Traqio;

$traqio = new Traqio(getenv('TRAQIO_SECRET_KEY'));
```

### Reportar el registro con su trackID

Llama a `signup()` una vez, donde se crea la cuenta. @traqio/web escribe el trackID en la cookie `traq_click` de tu propio dominio, así que el navegador lo envía con la petición de registro; `TrackId::fromRequest()` lo lee.

Laravel:
```php
use Illuminate\Http\Request;
use Traqio\Laravel\Facades\Traqio;
use Traqio\TraqioException;
use Traqio\TrackId;

public function store(Request $request)
{
    $user = User::create($request->validated());

    try {
        // Reads the raw Cookie header: Laravel's cookie decryption would drop traq_click.
        Traqio::signup((string) $user->id, TrackId::fromRequest($request));
    } catch (TraqioException $e) {
        report($e); // never fail the sign-up itself
    }

    return redirect('/welcome');
}
```

PHP:
```php
use Traqio\TrackId;

$user = $users->create($_POST);
$result = $traqio->signup((string) $user->id, TrackId::fromRequest()); // the current request
```

En Laravel, para sacar la llamada de la petición, ejecútala después de enviar la respuesta:

```php
dispatch(fn () => Traqio::signup((string) $user->id, $trackId))->afterResponse();
```

Si el backend está en otro dominio que el sitio, la cookie no le llega: envía en su lugar `Traqio.getTrackId()` desde el navegador con el formulario. El registro es el momento en que el usuario es **captado**; el último clic anterior, dentro de tu [ventana de atribución](https://traqio.app/es/docs/concepts/attribution-windows), se lleva el crédito.

### Registrar las conversiones

```php
Traqio::track((string) $user->id, 'purchase', [
    'value' => 49,
    'currency' => 'EUR',
    'transactionId' => $paymentIntent->id, // one payment, one row — whoever reports it
    'store' => 'stripe',
]);
```

Las conversiones siguen al usuario: se acreditan a la campaña que lo captó.

## Qué te dice la respuesta

```php
$result = Traqio::signup((string) $user->id, $trackId);

$result->trackId;                 // "matched" | "unknown" | "expired" | "claimed" | "refused" | null
$result->acquired;                // true: the sign-up is recorded
$result->attribution->network;    // "meta", "tiktok"… or "organic"
$result->attribution->campaignId; // the campaign that brought the user
```

| trackId | Significado |
| --- | --- |
| matched | El clic pertenece ahora a este usuario. Un reintento vuelve a responder matched. |
| unknown | Ningún clic de este producto tiene ese id — una errata, un enlace de otro producto o un valor que no escribió @traqio/web. |
| expired | El clic es más antiguo que la ventana de atribución del producto. |
| claimed | Otro usuario, o una instalación de app, ya tiene ese clic. Un clic acredita una sola identidad. |
| refused | El clic no superó una regla antifraude (pasó por una red de anonimización). Se contabiliza, nunca se acredita. |

## Qué hace hoy y qué no

|  | Hoy |
| --- | --- |
| Vincular un registro a su clic e indicar a quién se acreditó | Sí — en la respuesta |
| Registrar compras con valor, moneda e id de pago, sin duplicados | Sí |
| Dejar intactas las instalaciones, los ingresos y el ROAS de tus apps | Sí — nunca se vincula a una instalación de app |
| Mostrar las conversiones web en los informes de la consola | Sí — por campaña, junto a las instalaciones |
| Enviar las conversiones web a Meta o TikTok | Todavía no |

Las conversiones enviadas aquí aparecen en **Eventos en directo**, marcadas como no vinculadas a una instalación — lo esperado para un sitio web. Un registro acreditado a una campaña se cuenta en el informe de ROAS como una conversión web de esa campaña, junto a sus instalaciones, y la respuesta de cada llamada te da la atribución al instante.

## Errores y reintentos

Un error de red, un timeout, un `429` o un `5xx` se reintenta — dos veces por defecto, con el mismo cuerpo, así que nada se cuenta dos veces. Un `4xx` (clave errónea o revocada, payload no válido) no se reintenta. Ambos terminan en una `Traqio\TraqioException`:

```php
use Traqio\TraqioException;

try {
    Traqio::signup((string) $user->id, $trackId);
} catch (TraqioException $e) {
    // $e->status: 401 = wrong or revoked key, 400 = invalid payload, null = network
    Log::warning($e->getMessage(), ['status' => $e->status, 'body' => $e->body]);
}
```

> **Reporta después de tu propia escritura** Llama a Traqio una vez guardada la cuenta o el pago, y nunca dejes que un error de Traqio lo haga fallar.

## Referencia de la API

config/traqio.php:
```php
// config/traqio.php
return [
    'secret_key'  => env('TRAQIO_SECRET_KEY'),                       // required
    'endpoint'    => env('TRAQIO_ENDPOINT', 'https://api.traqio.app'),
    'timeout'     => (float) env('TRAQIO_TIMEOUT', 10),               // seconds per attempt
    'max_retries' => (int) env('TRAQIO_MAX_RETRIES', 2),              // network error, 429, 5xx
];
```

| Método | Qué hace |
| --- | --- |
| signup($userId, $trackId = null, $events = []) | Reporta el registro — la captación — con su trackID. Se conserva el primero. |
| track($userId, $name, $properties = []) | Registra una conversión: value, currency, transactionId, store, eventId, trackId. |
| send($input) | La llamada en bruto detrás de ambos, para varios eventos a la vez. |
| TrackId::fromRequest($request = null) | El trackID de una petición Laravel, Symfony o PSR-7 — o de la petición PHP actual — o null. |

En PHP simple, las mismas opciones son el segundo argumento del constructor: `endpoint`, `timeout`, `max_retries` y `transport` para enviar las peticiones a través de tu propio cliente HTTP.

> **Nivel de prueba** Probado con PHPUnit — la integración Laravel en Laravel 12 y 13, el cliente en PHP 8.1 y 8.5 — y ejecutado de principio a fin contra una API de Traqio en funcionamiento: un registro con trackID volvió matched con su campaña, un segundo usuario que reclamaba el mismo clic recibió claimed, una clave errónea fue rechazada. Todavía no se ha ejecutado en el backend de producción de un cliente.

## Preguntas frecuentes

**¿Por qué $request->cookie('traq_click') devuelve null en Laravel?**
Laravel cifra sus cookies y las descifra en cada petición; una cookie escrita por JavaScript — la que pone @traqio/web — no supera ese descifrado, así que Laravel devuelve null. TrackId::fromRequest lee en su lugar la cabecera Cookie en bruto, que el descifrado nunca toca. No hace falta añadir traq_click a las excepciones de EncryptCookies.

**¿Qué versiones de Laravel son compatibles?**
Laravel 12 y 13, mediante el descubrimiento automático de paquetes: el service provider, el archivo de configuración y la facade Traqio se registran solos. El cliente en sí es PHP 8.1+ simple y funciona en Symfony, Slim o cualquier aplicación PSR-7.

**¿Y si el visitante no vino de un anuncio?**
TrackId::fromRequest devuelve null y el registro se guarda igualmente, como orgánico: no se acredita ninguna campaña.

**¿Un reintento contará una compra dos veces?**
No. Cada llamada genera sus ids de evento una sola vez y reintenta exactamente el mismo cuerpo, y una compra se identifica además por su transactionId, así que el mismo pago reportado dos veces se guarda una sola vez.
