API v1 · Guia
Idempotência
Repita POST, PATCH e DELETE com segurança usando o cabeçalho Idempotency-Key.
A conexão cai depois que o pedido chegou e antes de a resposta voltar. Sem idempotência, repetir pode criar o registro duas vezes. Com o cabeçalho Idempotency-Key, a segunda tentativa devolve a resposta da primeira e nada roda de novo.
Para repetir com segurança um POST, PATCH ou DELETE (depois de uma queda de
conexão, por exemplo), envie o cabeçalho Idempotency-Key com um valor único por
operação, como um UUID. O cabeçalho é opcional.
- Mesma chave e mesmo pedido (método, caminho e corpo idênticos, byte a byte) dentro de
24 horas: a operação não roda de novo. Você recebe a resposta guardada da primeira vez,
com o cabeçalho
Idempotent-Replayed: true. - Mesma chave com outro pedido:
409 idempotency_key_reused. Gere uma chave nova. - Mesma chave enquanto o primeiro pedido ainda está em andamento:
409 idempotency_key_in_progress. Espere a resposta do primeiro e repita. - Respostas
429e de erro5xxnão ficam guardadas: repetir com a mesma chave executa de novo. Os demais erros4xxficam guardados como qualquer resposta.
A chave vale só para o token que a enviou. Em pedidos GET ela é ignorada.
Exemplo
Terminal
curl -X POST "https://rumocrm.com/api/v1/contacts" \
-H "Authorization: Bearer $RUMO_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2d7e-8a4b-4c3d-9e2f-0a1b2c3d4e5f" \
-d '{"name": "Maria Souza", "phone": "(15) 99807-3400"}'Repetir com a mesma chave
Gere a chave uma vez por operação e guarde junto dela (na fila, por exemplo). Uma chave nova a cada tentativa desliga a proteção.
Node.js
import { randomUUID } from "node:crypto";
// A chave nasce junto com a operação, antes da primeira tentativa, e vai em todas.
async function criarContato(dados, tentativas = 4) {
const chave = randomUUID();
for (let tentativa = 1; ; tentativa++) {
try {
const resposta = await fetch("https://rumocrm.com/api/v1/contacts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RUMO_TOKEN}`,
"Content-Type": "application/json",
"Idempotency-Key": chave,
},
body: JSON.stringify(dados),
});
if (resposta.status < 500 || tentativa === tentativas) return resposta;
} catch (erroDeRede) {
if (tentativa === tentativas) throw erroDeRede;
}
await new Promise((pronto) => setTimeout(pronto, 2 ** tentativa * 500));
}
}