Referencia de la API

Callbacks

Callbacks de finalización firmados.

Un callback avisa a tu servidor cuando una ejecución ha terminado, de modo que no necesitas hacer polling ni mantener abierto un flujo de eventos. Ephemeral envía una solicitud POST firmada con el objeto de la ejecución cuando esta alcanza un estado final.

Solicitar un callback

Añade callback a la solicitud de ejecución.

callback.urlstringobligatorio
Tu endpoint. Debe usar HTTPS y resolverse a una dirección pública. No se siguen las redirecciones.
callback.secretstringobligatorio
De 24 a 1024 caracteres, se usa para firmar cada entrega. Genera un valor aleatorio y guárdalo en tu servidor.
JSON
{
  "workflow": "investigate-payment",
  "input": { "payment_id": "pay_123" },
  "max_cost_micros": 500000,
  "callback": {
    "url": "https://example.com/hooks/ephemeral",
    "secret": "3f9a6c1e8b2d47f0a5c3e9d1b7f2a6c4"
  }
}

El secreto nunca se devuelve en ninguna lectura, ni siquiera en la definición de la ejecución. Los callbacks no forman parte de los flujos de trabajo guardados; configura uno en cada ejecución que lo necesite.

Qué recibes

El cuerpo es el objeto de la ejecución tal como está en el momento de la entrega, enviado como JSON con estas cabeceras:

CabeceraValor
X-Ephemeral-RunEl ID de la ejecución.
X-Ephemeral-TimestampHora Unix en segundos en la que se firmó este intento.
X-Ephemeral-Signaturesha256= seguido del HMAC-SHA256 en hexadecimal de la marca de tiempo, un punto y el cuerpo sin procesar, con tu secreto como clave.
Content-Typeapplication/json
Contenido firmado
<X-Ephemeral-Timestamp>.<raw request body>

Verificar la firma

Calcula el HMAC sobre los bytes sin procesar del cuerpo antes de analizarlo y compara en tiempo constante.

Node.js with Express
import crypto from "node:crypto";
import express from "express";

const app = express();

app.post("/hooks/ephemeral", express.raw({ type: "application/json" }), (req, res) => {
  const timestamp = req.get("X-Ephemeral-Timestamp") ?? "";
  const signature = req.get("X-Ephemeral-Signature") ?? "";
  const expected =
    "sha256=" +
    crypto
      .createHmac("sha256", process.env.EPHEMERAL_CALLBACK_SECRET)
      .update(timestamp + ".")
      .update(req.body)
      .digest("hex");

  const valid =
    signature.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
  const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) < 300;
  if (!valid || !fresh) return res.sendStatus(401);

  const run = JSON.parse(req.body);
  // Record run.id first and skip it if you have already handled it.
  res.sendStatus(204);
});

Cada intento se firma con la hora actual, así que rechazar las marcas de tiempo antiguas limita los ataques de repetición sin rechazar los reintentos legítimos.

Entrega y reintentos

Cualquier respuesta 2xx cuenta como entregada. Cualquier otra, incluidos un tiempo de espera agotado o una redirección, se reintenta: primero a los 10 segundos y después duplicando la espera cada vez, hasta unos 43 minutos entre intentos. Las entregas pendientes se almacenan de forma duradera, así que un reinicio del motor no las pierde.

Deduplica por ID de ejecución
Tu endpoint puede recibir la misma ejecución más de una vez, por ejemplo cuando procesó una entrega pero la respuesta se perdió. Usa X-Ephemeral-Run para que el procesamiento sea idempotente.
Un callback puede llegar antes de que la facturación se haya liquidado. Si billing_pending es true en el cuerpo, vuelve a leer la ejecución más tarde con GET /v1/runs/{id} para obtener su coste final.
© 2026 EphemeralProducido por erni.works
esc

Nada coincide con “”.