Idempotencia
Reintentar un POST /pipelines/from-intent sin coordinarte con el servidor crea dos pipelines. Para evitarlo, cada call mutativo del Agent API acepta un campo idempotency_key en el body (16–128 caracteres).
Repetir con la misma key devuelve el mismo run_id / pipeline_id / artifact — nunca uno nuevo.
Dónde vive la key
| Endpoint | Campo |
|---|---|
POST /pipelines/from-intent | body idempotency_key |
POST /posts/{id}/draft | body idempotency_key |
POST /artifacts/{id}/publish | body idempotency_key |
POST /x-accounts/connect | body idempotency_key |
POST /scrape | body idempotency_key (opcional — repetir pares (url, intent) pega al response cache igual) |
Los endpoints read-only (GET /pipelines/{id}, GET /pipelines/{id}/inbox, etc.) ignoran el campo.
Las tools MCP espejan el mismo parámetro — cada tool mutativa expone
idempotency_keycon la misma semántica. Ver MCP · tools.
Formato
| Propiedad | Detalle |
|---|---|
| Longitud | 16–128 caracteres. Más corto o más largo devuelve validation_failed. |
| Charset | ASCII libre. Hex de UUIDv4 (32 chars después de quitar dashes) es el shape recomendado. |
| Scope | (organization_id, endpoint, key). Dos orgs distintas pueden usar la misma key sin colisionar. |
| TTL | El servidor guarda la respuesta original durante la vida del recurso subyacente — replays después de borrar el recurso devuelven 404 not_found, no un body cacheado. |
Estados de replay
| Situación | Resultado |
|---|---|
| Misma key + mismo body + original completado | Devuelve el mismo run_id / id de recurso que el primer call. Los side effects no se repiten. |
| Misma key + body distinto | El endpoint devuelve su error normal (típicamente validation_failed) — las keys no están atadas al shape del body, pero las invariantes subyacentes siguen aplicando. |
| Misma key + original todavía corriendo | El call devuelve el run_id del original. Polleá ese run; no generes una key nueva. |
Hoy no hay HTTP 409 idempotency_request_in_progress — from-intent devuelve inmediatamente con el pipeline existente + el run id original.
Patrón recomendado en el cliente
- Generá un UUIDv4 al inicio del intento lógico.
- Reusalo en cada retry de ese mismo intento.
- Generá uno nuevo solo cuando el usuario vuelva a accionar con intención (es acción nueva, no retry).
const idempotencyKey = crypto.randomUUID().replaceAll("-", "");
// hex de 32 chars — holgadamente dentro del rango 16–128.
await fetch(`${WHET_BASE_URL}/pipelines/from-intent`, {
method: "POST",
headers: {
"Authorization": `Bearer ${WHET_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
handle: "growth_dr",
intent: "Track for analytical drafts, daily.",
idempotency_key: idempotencyKey,
}),
});
Lo que no es
- No es un cache de aplicación. No lo uses para "saltarte" requests porque ya sabés la respuesta — el servidor sigue validando invariantes.
- No sobrevive para siempre. Una vez borrado el recurso subyacente, los replays devuelven
404 not_found. - No aplica a
GET,PATCHniDELETE. Asegurate de que esos reintentos sean idempotentes del lado tuyo.
Ver también: Autenticación, Taxonomía de errores.