Iniciar sesión Crear cuenta
Referencia de la API

Webhooks

Endpoints de webhook, eventos entregados, intentos y reenvío.

Registra URLs para recibir eventos en tiempo real. Cómo verificar la firma, los formatos de cada evento y la política de reintentos están en la guía de Webhooks.

El número de webhooks lo da el plan (webhooks): crear uno por encima del límite responde 403 plan_limit_reached. Si el plan baja de lo que tiene el equipo, los webhooks más nuevos por encima del límite quedan con paused_by_plan: true: siguen en la lista y se pueden leer y eliminar, pero no reciben eventos y no se pueden modificar, probar ni rotar su secreto (403 paused_by_plan). Vuelven solos cuando el plan o el recuento lo permiten.

#Listar webhooks

GET/webhooks

Clave de acceso total

Acepta limit, after y before. El secreto de firma no aparece en la lista. status es enabled o disabled y, si está desactivado, disabled_reason dice por qué: manual (pausado por una persona) o failing (desactivado por fallos seguidos).

GET /webhooks

cURL

curl https://api.postal.so/webhooks \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/webhooks', {
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.get(
    "https://api.postal.so/webhooks",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->get('webhooks', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Respuesta
{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "object": "webhook",
      "id": "0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b",
      "paused_by_plan": false,
      "endpoint": "https://lojaexemplo.com.br/webhooks/postal",
      "events": ["email.delivered", "email.bounced", "email.complained"],
      "skip_sources": [],
      "status": "enabled",
      "disabled_reason": null,
      "disabled_at": null,
      "failing_since": null,
      "last_success_at": "2026-10-24T13:02:14.000000Z",
      "created_at": "2026-10-03T10:00:00.000000Z"
    }
  ]
}

#Crear un webhook

POST/webhooks

Clave de acceso total

Registra el endpoint y devuelve el signing_secret (whsec_…) usado para firmar las entregas.

Cuerpo de la solicitud

  • endpointstringobligatorio
    URL HTTPS pública, hasta 2048 caracteres. Las direcciones de red privada se rechazan en la entrega.
  • eventsstring[]obligatorio
    Uno o más tipos de evento, sin repetir: email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.opened, email.clicked, email.replied, email.failed, email.scheduled, email.suppressed, email.received, domain.created, domain.updated, domain.deleted, suppression.added, suppression.removed, contact.created, contact.updated, contact.deleted, contact.segment_entered, contact.segment_exited, form.submitted, broadcast.sent, sending.paused, sending.resumed, inbox.thread.created, inbox.thread.updated, inbox.thread.deleted, inbox.draft.created. Cuándo ocurre cada uno: guía de webhooks.
  • skip_sourcesstring[]
    Hasta 20 orígenes de cambio que este endpoint no debe recibir en los eventos contact.created, contact.updated y contact.deleted. Cada origen tiene hasta 64 caracteres (letras minúsculas, números, ., _, : o -) y puede terminar en * para valer como prefijo, como crm:*. Sirve para que un sistema que sincroniza en los dos sentidos no reciba de vuelta los cambios que él mismo hizo: mira el origen de los cambios.

Errores

  • 403plan_limit_reached
    El equipo ya tiene el número de webhooks que permite el plan.
  • 422validation_error
    URL que no es HTTPS, lista vacía, evento desconocido o repetido, u origen con formato no válido.
POST /webhooks

cURL

curl -X POST https://api.postal.so/webhooks \
  -H "Authorization: Bearer $POSTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "endpoint": "https://lojaexemplo.com.br/webhooks/postal",
    "events": ["email.delivered", "email.bounced", "email.complained"]
  }'

Node.js

const response = await fetch('https://api.postal.so/webhooks', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    endpoint: 'https://lojaexemplo.com.br/webhooks/postal',
    events: ['email.delivered', 'email.bounced', 'email.complained'],
  }),
});

const data = await response.json();

Python

import os
import requests

response = requests.post(
    "https://api.postal.so/webhooks",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    json={
        "endpoint": "https://lojaexemplo.com.br/webhooks/postal",
        "events": ["email.delivered", "email.bounced", "email.complained"],
    },
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->post('webhooks', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
    'json' => [
        'endpoint' => 'https://lojaexemplo.com.br/webhooks/postal',
        'events' => ['email.delivered', 'email.bounced', 'email.complained'],
    ],
]);

$data = json_decode($response->getBody(), true);
201Respuesta
{
  "object": "webhook",
  "id": "0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b",
  "signing_secret": "whsec_c2VncmVkby1kZS1leGVtcGxvLTEyMzQ1Ng=="
}

#Obtener un webhook

GET/webhooks/{id}

Clave de acceso total

Devuelve el webhook con el signing_secret actual.

Parámetros de ruta

  • idstringobligatorio
    ID del webhook.

Errores

  • 404not_found
    El recurso no existe o es de otro equipo.
GET /webhooks/{id}

cURL

curl https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b', {
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.get(
    "https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->get('webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Respuesta
{
  "object": "webhook",
  "id": "0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b",
  "paused_by_plan": false,
  "endpoint": "https://lojaexemplo.com.br/webhooks/postal",
  "events": ["email.delivered", "email.bounced", "email.complained"],
  "skip_sources": [],
  "status": "enabled",
  "disabled_reason": null,
  "disabled_at": null,
  "failing_since": null,
  "last_success_at": "2026-10-24T13:02:14.000000Z",
  "created_at": "2026-10-03T10:00:00.000000Z",
  "signing_secret": "whsec_c2VncmVkby1kZS1leGVtcGxvLTEyMzQ1Ng=="
}

#Actualizar un webhook

PATCH/webhooks/{id}

Clave de acceso total

Cambia la URL o los eventos, o pausa el webhook. Con disabled, no se entrega ningún evento (ni los reintentos pendientes) y disabled_reason queda en manual. {"status": "enabled"} reactiva un webhook pausado o desactivado por fallos y limpia disabled_reason y failing_since.

Parámetros de ruta

  • idstringobligatorio
    ID del webhook.

Cuerpo de la solicitud

  • endpointstring
    Nueva URL HTTPS.
  • eventsstring[]
    Nueva lista de eventos (sustituye a la anterior).
  • skip_sourcesstring[] | null
    Nueva lista de orígenes que ignorar (mismas reglas de Crear un webhook). Envía [] o null para vaciarla.
  • statusstring
    enabled o disabled.

Errores

  • 403paused_by_plan
    El webhook está pausado porque el equipo superó el límite del plan. Elimina otros webhooks o cambia de plan.
  • 422validation_error
    Algún campo no es válido. El mensaje indica cuál.
  • 404not_found
    El recurso no existe o es de otro equipo.
PATCH /webhooks/{id}

cURL

curl -X PATCH https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b \
  -H "Authorization: Bearer $POSTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "disabled"
  }'

Node.js

const response = await fetch('https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    status: 'disabled',
  }),
});

const data = await response.json();

Python

import os
import requests

response = requests.patch(
    "https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    json={
        "status": "disabled",
    },
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->patch('webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
    'json' => [
        'status' => 'disabled',
    ],
]);

$data = json_decode($response->getBody(), true);
200Respuesta
{
  "object": "webhook",
  "id": "0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b"
}

#Eliminar un webhook

DELETE/webhooks/{id}

Clave de acceso total

Parámetros de ruta

  • idstringobligatorio
    ID del webhook.

Errores

  • 404not_found
    El recurso no existe o es de otro equipo.
DELETE /webhooks/{id}

cURL

curl -X DELETE https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.delete(
    "https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->delete('webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Respuesta
{
  "object": "webhook",
  "id": "0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b",
  "deleted": true
}

#Rotar el secreto de firma

POST/webhooks/{id}/signing-secret/rotate

Clave de acceso total

Genera un nuevo signing_secret, que vale de inmediato. Actualiza tu servidor enseguida: las entregas firmadas con el secreto nuevo fallan en la verificación con el antiguo.

Parámetros de ruta

  • idstringobligatorio
    ID del webhook.

Errores

  • 403paused_by_plan
    El webhook está pausado por el plan.
  • 404not_found
    El recurso no existe o es de otro equipo.
POST /webhooks/{id}/signing-secret/rotate

cURL

curl -X POST https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/signing-secret/rotate \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/signing-secret/rotate', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.post(
    "https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/signing-secret/rotate",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->post('webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/signing-secret/rotate', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Respuesta
{
  "object": "webhook",
  "id": "0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b",
  "signing_secret": "whsec_bm92by1zZWdyZWRvLWRlLWV4ZW1wbG8tOTg3Ng=="
}

#Enviar un evento de prueba

POST/webhooks/{id}/test

Clave de acceso total

Envía al instante un evento webhook.test al endpoint, firmado como los demás, para que compruebes la URL y la verificación de la firma. Es un solo intento, sin reintentos, y vale incluso con el webhook desactivado. Aparece en la lista de eventos y no cuenta para la desactivación automática.

Parámetros de ruta

  • idstringobligatorio
    ID del webhook.

Errores

  • 403paused_by_plan
    El webhook está pausado por el plan.
  • 404not_found
    El recurso no existe o es de otro equipo.
POST /webhooks/{id}/test

cURL

curl -X POST https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/test \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/test', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.post(
    "https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/test",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->post('webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/test', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
202Respuesta
{
  "object": "webhook_event",
  "id": "019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c",
  "type": "webhook.test"
}

#Listar eventos de un webhook

GET/webhooks/{id}/events

Clave de acceso total

Los eventos enviados a este webhook en los últimos 30 días, con el estado de la entrega: pending, attempting (falló y tiene un nuevo intento en next_attempt_at), success o failed (agotó los intentos o el webhook se desactivó). Acepta limit, after y before.

Parámetros de ruta

  • idstringobligatorio
    ID del webhook.

Errores

  • 404not_found
    El recurso no existe o es de otro equipo.
GET /webhooks/{id}/events

cURL

curl https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events', {
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.get(
    "https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->get('webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Respuesta
{
  "object": "list",
  "has_more": true,
  "data": [
    {
      "object": "webhook_event",
      "id": "019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c",
      "type": "email.delivered",
      "created_at": "2026-10-24T13:02:14.000000Z",
      "status": "success",
      "attempts": 1,
      "next_attempt_at": null
    }
  ]
}

#Obtener un evento

GET/webhooks/{id}/events/{event_id}

Clave de acceso total

Devuelve el evento con el payload exacto que se envió (o se enviará).

Parámetros de ruta

  • idstringobligatorio
    ID del webhook.
  • event_idstringobligatorio
    ID del evento.

Errores

  • 404not_found
    El recurso no existe o es de otro equipo.
GET /webhooks/{id}/events/{event_id}

cURL

curl https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events/019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events/019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c', {
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.get(
    "https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events/019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->get('webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events/019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Respuesta
{
  "object": "webhook_event",
  "id": "019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c",
  "type": "email.delivered",
  "created_at": "2026-10-24T13:02:14.000000Z",
  "status": "success",
  "attempts": 1,
  "next_attempt_at": null,
  "payload": {
    "type": "email.delivered",
    "created_at": "2026-10-24T13:02:14.120Z",
    "data": {
      "email_id": "019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b",
      "created_at": "2026-10-24T13:02:11.000Z",
      "from": "Loja Exemplo <[email protected]>",
      "to": ["[email protected]"],
      "subject": "Seu pedido #10482 saiu para entrega",
      "tags": {
        "category": "shipping"
      }
    }
  }
}

#Listar intentos de entrega

GET/webhooks/{id}/events/{event_id}/attempts

Clave de acceso total

Cada intento de entrega con el estado HTTP, el inicio de la respuesta de tu servidor (hasta 2.000 caracteres), el error de conexión, si lo hubo, y la duración.

Parámetros de ruta

  • idstringobligatorio
    ID del webhook.
  • event_idstringobligatorio
    ID del evento.

Errores

  • 404not_found
    El recurso no existe o es de otro equipo.
GET /webhooks/{id}/events/{event_id}/attempts

cURL

curl https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events/019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c/attempts \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events/019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c/attempts', {
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.get(
    "https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events/019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c/attempts",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->get('webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events/019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c/attempts', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Respuesta
{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "id": "019a1b2c-5e70-7b91-8c2d-3e4f5a6b7c8d",
      "http_status_code": 200,
      "response": "{\"ok\":true}",
      "error": null,
      "duration_ms": 184,
      "sent_at": "2026-10-24T13:02:14.000000Z"
    }
  ]
}

#Reenviar un evento

POST/webhooks/{id}/events/{event_id}/replay

Clave de acceso total

Entrega el evento de nuevo al instante, aunque ya haya salido bien o haya fallado definitivamente. El contador de intentos se reinicia. La entrega usa el mismo ID de mensaje (webhook-id), así que tu servidor puede reconocer la repetición. Con el webhook desactivado no se entrega nada: reactívalo antes, con PATCH /webhooks/{id}.

Parámetros de ruta

  • idstringobligatorio
    ID del webhook.
  • event_idstringobligatorio
    ID del evento.

Errores

  • 403paused_by_plan
    El webhook está pausado por el plan.
  • 404not_found
    El recurso no existe o es de otro equipo.
POST /webhooks/{id}/events/{event_id}/replay

cURL

curl -X POST https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events/019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c/replay \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events/019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c/replay', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
  },
});

const data = await response.json();

Python

import os
import requests

response = requests.post(
    "https://api.postal.so/webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events/019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c/replay",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->post('webhooks/0199f6d2-3c4d-7e5f-8a6b-7c8d9e0f1a2b/events/019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c/replay', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Respuesta
{
  "object": "webhook_event",
  "id": "019a1b2c-5e6f-7a80-9b1c-2d3e4f5a6b7c"
}