Saltar al contenido
Empezar gratis
Menú
API de servidor

API de servidor

Última actualización: 13 nov 2026

Confirma una conversión desde tu backend con una petición HTTP autenticada con la clave de servidor del proyecto. No necesitas ningún SDK de servidor.

La evidencia del navegador puede perderse: una pestaña se cierra durante el pago, una extensión bloquea la solicitud o falla la red. Confirmar la conversión desde tu backend cubre ese hueco. La evidencia del navegador y la del servidor cuentan como una sola conversión porque comparten el mismo identificador estable.

Envía la conversión desde tu servidor con una petición HTTP y la clave de servidor del proyecto. No hay ningún SDK de servidor que instalar. Si instalas con una etiqueta script o con npm, Instalación y claves, en tu proyecto, te da la petición con las conversiones de tu recorrido ya puestas.

Endpoint

https://api.tracelog.io/v1/server/events

Envía un POST con Content-Type: application/json y la clave de servidor del proyecto como bearer token en Authorization:

HTTP

Authorization: Bearer tl_sk_xxxxxxxxxxxxxxxxxxxxxxxxxx

La clave es secreta. No está limitada a las direcciones de tu web, permite escribir eventos a cualquiera que la posea y nunca debe llegar al bundle del navegador. Rótala desde la página Instalación y claves del proyecto; el valor solo se muestra al crearla o rotarla.

El payload

JSON

{
  "v": 1,
  "events": [
    {
      "eventId": "019b9ae7-2c00-7000-8000-000000000001",
      "sessionId": "019b9ae7-2c00-7000-8000-000000000002",
      "kind": "conversion",
      "name": "purchase",
      "occurredAt": "2026-01-08T00:00:00.000Z",
      "identifier": "wc-1042",
      "value": 129.5,
      "currency": "EUR"
    }
  ]
}
CampoTipoDescripción
v1Versión del payload. Una versión desconocida se rechaza como unknown_version; nunca se interpreta por aproximación.
eventIdUUID v7Clave de idempotencia. Reenviar el mismo valor no duplica el recuento, por lo que es seguro reintentar tras un timeout.
sessionIdUUID v7Créalo y guárdalo con la conversión. El código de captura no expone la sesión del navegador, y la confirmación del servidor no la necesita.
kindstringconversion, step, session_start o error.
namestringNombre en el recorrido de conversión: minúsculas, empezar por una letra y continuar con letras, números o guiones bajos, hasta 64 caracteres.
occurredAtISO 8601Momento del evento en UTC y con milisegundos. TraceLog asigna el evento a esta hora, no a la de llegada.
identifierstringObligatorio para conversiones, entre 1 y 256 caracteres. Tu identificador estable.
valuenumberOpcional, igual o mayor que cero.
currencystringOpcional, código ISO 4217 de tres letras mayúsculas.
itemsarrayOpcional, en una conversión o un paso: hasta 100, cada uno con un ID, un nombre, una categoría opcional, una cantidad desde 1 y un precio unitario opcional.
scheduledForstringOpcional, en una conversión: para qué día es, AAAA-MM-DD.
recurringbooleanOpcional, en una conversión: si es periódica.
firstbooleanOpcional, en una conversión: true si tus registros no tienen ninguna conversión anterior de este tipo hecha por la misma persona, false si la tienen; omítelo si no lo sabes.
modestringOpcional. verification marca tráfico de verificación, que no cuenta en las métricas ni en el límite de sesiones. Úsalo cuando el modo de prueba de tu sistema haya generado el pedido.
contextobjectOpcional. Objeto serializable como JSON, hasta 8 KB.

Una conversión necesita seis campos: eventId, sessionId, kind, name, occurredAt e identifier. Cada lote admite como máximo 50 eventos y cada solicitud, 256 KB. Se rechaza un evento situado más de cinco minutos en el futuro. Si tiene más de siete días, se acepta pero queda marcado como tardío.

Si items, scheduledFor, recurring o first están mal formados, se descartan y el evento se conserva. Cuando tu servidor y el navegador envían artículos de una misma conversión, TraceLog se queda con los de tu servidor si su occurredAt cae en el día en que se hizo la conversión, según la zona horaria del proyecto. Un artículo cuyo ID es (other) se cuenta en «Otros», junto con los que pasan de los 500 de cada día.

Respuesta

JSON

{ "accepted": 1, "rejected": [] }

accepted cuenta los eventos que esa solicitud ha guardado. Un solo evento no válido rechaza el lote completo: no se guarda nada, y rejected enumera cada eventId que haya podido leerse con el motivo del lote (unknown_version, invalid_schema o future_time). Un eventId o un sessionId que no sea un UUID v7 es invalid_schema.

Las cifras de un día admiten eventos tardíos durante 30 días. Un evento de hace más de 30 días es expired: se rechaza él solo y el resto del lote se guarda.

Una solicitud de más de 256 KB o de más de 50 eventos se rechaza entera con un HTTP 413 y sin recibo: eso es too_large. Si una misma clave envía demasiadas solicitudes, recibe un HTTP 429 con una cabecera Retry-After en segundos.

Ejemplos

Los ejemplos leen dos variables: TRACELOG_API, con el valor https://api.tracelog.io, y TRACELOG_SERVER_KEY, la clave de servidor del proyecto.

Comando

curl -X POST "$TRACELOG_API/v1/server/events" \
  -H "Authorization: Bearer $TRACELOG_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "v": 1,
    "events": [{
      "eventId": "019b9ae7-2c00-7000-8000-000000000001",
      "sessionId": "019b9ae7-2c00-7000-8000-000000000002",
      "kind": "conversion",
      "name": "purchase",
      "occurredAt": "2026-01-08T00:00:00.000Z",
      "identifier": "1042",
      "value": 129.5,
      "currency": "EUR"
    }]
  }'
JavaScript

await fetch(`${process.env.TRACELOG_API}/v1/server/events`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TRACELOG_SERVER_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    v: 1,
    events: [
      {
        // UUID v7 generado una vez por pedido y guardado con él. En
        // Node, v7() del paquete uuid genera uno; crypto.randomUUID()
        // genera un v4, que TraceLog rechaza.
        eventId: order.eventId,
        sessionId: order.sessionId,
        kind: "conversion",
        name: "purchase",
        occurredAt: new Date().toISOString(),
        identifier: order.number,
        value: order.total,
        currency: order.currency,
      },
    ],
  }),
});
PHP

<?php
// Un UUID v7: milisegundos Unix, versión, variante y bits aleatorios.
function uuid_v7()
{
    $ms = (int) floor(microtime(true) * 1000);
    $hex = str_pad(dechex($ms), 12, '0', STR_PAD_LEFT);
    $hex .= bin2hex(random_bytes(10));
    $hex[12] = '7';
    $hex[16] = dechex(8 | (hexdec($hex[16]) & 3));
    return preg_replace('/^(.{8})(.{4})(.{4})(.{4})/', '$1-$2-$3-$4-', $hex);
}

// Genera los dos una vez, al crear el pedido, y guárdalos con él.
$order['tracelog_event_id'] = uuid_v7();
$order['tracelog_session_id'] = uuid_v7();

// Cuando se confirme el pago:
$curl = curl_init(getenv('TRACELOG_API') . '/v1/server/events');
curl_setopt_array($curl, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('TRACELOG_SERVER_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'v' => 1,
        'events' => [[
            'eventId' => $order['tracelog_event_id'],
            'sessionId' => $order['tracelog_session_id'],
            'kind' => 'conversion',
            'name' => 'purchase',
            'occurredAt' => gmdate('Y-m-d\TH:i:s.000\Z'),
            'identifier' => (string) $order['number'],
            'value' => (float) $order['total'],
            'currency' => $order['currency'],
        ]],
    ]),
]);
$response = curl_exec($curl);
curl_close($curl);
Python

import json, os, urllib.request

request = urllib.request.Request(
    f"{os.environ['TRACELOG_API']}/v1/server/events",
    method="POST",
    headers={
        "Authorization": f"Bearer {os.environ['TRACELOG_SERVER_KEY']}",
        "Content-Type": "application/json",
    },
    data=json.dumps({
        "v": 1,
        "events": [{
            # UUID v7 guardado con el pedido
            "eventId": order.tracelog_event_id,
            "sessionId": session_id,
            "kind": "conversion",
            "name": "purchase",
            "occurredAt": occurred_at,
            "identifier": str(order.number),
            "value": float(order.total),
            "currency": order.currency,
        }],
    }).encode(),
)
urllib.request.urlopen(request)

Reintentos

Reintenta tras un error de red, una respuesta 5xx o un 429 una vez pasado su Retry-After, siempre con el mismo eventId. El eventId es la clave de idempotencia: una entrega repetida se guarda y se cuenta una sola vez. Con un eventId nuevo, el reintento se contaría otra vez.

Pagos fallidos

Cuando tu backend vea que falla un pago, puede avisar a TraceLog, con la misma clave de servidor, con un POST a:

https://api.tracelog.io/v1/server/payment-failure
JSON

{ "gateway": "redsys", "occurredAt": "2026-11-04T10:15:30.000Z" }

gateway es el nombre del método de pago, de 1 a 100 caracteres sin los espacios de los extremos. occurredAt puede tener como mucho 48 horas de antigüedad y adelantarse cinco minutos como mucho. TraceLog guarda un recuento por día y pasarela y nada más del pedido, así que no envíes ni número de pedido, ni importe, ni dirección. Una tarjeta rechazada y reintentada cuenta dos veces.

  • 204: guardado.
  • 400: el cuerpo no es como el de arriba. Su refusal es payment_failure_invalid.
  • 401: la clave falta, es desconocida, está revocada o no es la de servidor.
  • 409: el proyecto está en Shopify, cuyo pago ya los comunica. Su refusal es payment_failure_channel.
  • 429: demasiadas solicitudes con esta clave, el límite que comparte con tus eventos, con una cabecera Retry-After en segundos.
  • 503: TraceLog no ha podido guardarlo.