Reenviar (clonando) Evento de Webhook
curl --request POST \
--url https://garu.com.br/api/v1/webhook-events/{uuid}/resend \
--header 'Authorization: Bearer <token>'import requests
url = "https://garu.com.br/api/v1/webhook-events/{uuid}/resend"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://garu.com.br/api/v1/webhook-events/{uuid}/resend', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://garu.com.br/api/v1/webhook-events/{uuid}/resend",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://garu.com.br/api/v1/webhook-events/{uuid}/resend"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://garu.com.br/api/v1/webhook-events/{uuid}/resend")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://garu.com.br/api/v1/webhook-events/{uuid}/resend")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyWebhooks e Exemplos
Reenviar (clonando) Evento de Webhook
Clona um evento e dispara a entrega imediatamente, preservando o original intacto
POST
/
api
/
v1
/
webhook-events
/
{uuid}
/
resend
Reenviar (clonando) Evento de Webhook
curl --request POST \
--url https://garu.com.br/api/v1/webhook-events/{uuid}/resend \
--header 'Authorization: Bearer <token>'import requests
url = "https://garu.com.br/api/v1/webhook-events/{uuid}/resend"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://garu.com.br/api/v1/webhook-events/{uuid}/resend', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://garu.com.br/api/v1/webhook-events/{uuid}/resend",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://garu.com.br/api/v1/webhook-events/{uuid}/resend"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://garu.com.br/api/v1/webhook-events/{uuid}/resend")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://garu.com.br/api/v1/webhook-events/{uuid}/resend")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyVisão Geral
Clona um evento de webhook e dispara a entrega imediatamente. O evento original não é tocado — fica no status terminal (success ou failed) com todo o histórico de tentativas e respostas preservado para auditoria. O clone é uma linha nova na tabela de eventos, carregando manualResendOf: <uuid_do_original>.
Disponível a partir da v0.11.0 (então em /api/webhook-events; migrado para /api/v1/webhook-events com identificador uuid).
Mudança de contrato no header
Idempotency-Key. Reenvios manuais (este endpoint e o botão “Reenviar” do dashboard) mandam Idempotency-Key: resend_<uuid> no POST para o seu endpoint, em vez do payload.id original.- Handlers que deduplicam pelo valor bruto do header já tratam isso como entrega fresca — nenhuma mudança de código. Mas vão começar a receber reenvios manuais que antes eram silenciosamente descartados; idempotência de negócio (orderId, transactionId) precisa absorver.
- Handlers que deduplicam pelo
payload.id(idêntico entre original e clone) ou normalizam o header precisam ser atualizados — caso contrário, o reenvio é descartado como duplicata.
/resend vs /retry
/resend | /retry | |
|---|---|---|
| Semântica | Clona o evento | Muta o evento original |
| Evento original | Intacto, status terminal preservado | Volta para pending, contador zerado |
| Histórico de respostas | Mantido no original | Sobrescrito pela nova tentativa |
Idempotency-Key outbound | resend_<uuid_do_clone> | event.payload.id (mesmo do original) |
| Indicado para | Tudo | Legado — preserve apenas se já automatizou em cima dele |
Exemplo de Requisição
curl -X POST https://garu.com.br/api/v1/webhook-events/a1b2c3d4-e5f6-7890-abcd-ef1234567890/resend \
-H "Authorization: Bearer sk_live_sua_chave_api"
import { Garu } from '@garuhq/node';
const garu = new Garu({ apiKey: process.env.GARU_API_KEY });
const clone = await garu.webhookEvents.resend('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
console.log(clone.uuid, clone.manualResendOf); // novo uuid, uuid do original
import os
import requests
response = requests.post(
"https://garu.com.br/api/v1/webhook-events/a1b2c3d4-e5f6-7890-abcd-ef1234567890/resend",
headers={"Authorization": f"Bearer {os.environ['GARU_API_KEY']}"},
)
clone = response.json()
print(clone["uuid"], clone["manualResendOf"]) # novo uuid, uuid do original
Parâmetros de Path
string
required
UUID do evento a clonar e reenviar. Funciona em qualquer status do evento original —
success, failed ou pending.Resposta
Retorna o clone recém-criado (não o original), em201 Created, já em pending e com a entrega disparada:
{
"uuid": "f9e8d7c6-b5a4-3210-9876-543210fedcba",
"webhookEndpoint": {
"id": 7,
"url": "https://example.com/webhooks/garu",
"description": "Produção",
"enabled": true,
"events": ["transaction.payment.succeeded"]
},
"eventType": "transaction.payment.succeeded",
"status": "pending",
"attempts": 0,
"lastAttemptAt": null,
"nextRetryAt": "2026-05-19T18:05:33.000Z",
"responseStatus": null,
"responseBody": null,
"manualResendOf": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"createdAt": "2026-05-19T18:04:33.000Z",
"payload": {
"id": "evt_1a2b3c",
"type": "transaction.payment.succeeded",
"data": { "object": { "id": 999, "value": 49.9 } }
}
}
Campos relevantes
| Campo | Tipo | Descrição |
|---|---|---|
uuid | string | Identificador do clone (novo). Use este uuid se quiser reenviar de novo. |
manualResendOf | string|null | uuid do evento original. Sempre presente em clones; null em eventos originais. |
status | string | Sempre pending na criação. Vira success ou failed conforme a entrega. |
payload | object | Cópia exata do payload do original — payload.id (evt_…) é preservado. |
O
payload.id (evt_…) do clone é idêntico ao do original. Quem muda é o Idempotency-Key HTTP outbound: o clone manda resend_<uuid_do_clone>, o original mandou evt_….Rate Limit
20 requisições por minuto por IP. Mesmo limite do/retry, mesma motivação: cada chamada dispara uma entrega HTTP síncrona para o endpoint do seller.
Erros
| Status | Caso |
|---|---|
| 404 | Evento não existe ou não pertence ao seller chamando |
| 429 | Rate limit excedido (mais de 20 resends/min do mesmo IP) |
Onde aparece no dashboard
Toda linha de evento em Configurações → Webhooks → Eventos mostra o botão Reenviar (visível emsuccess, failed e pending). Reenviar um evento já success abre uma confirmação (“este evento já foi entregue com sucesso — reenviar mesmo assim?”). Clones recebem um badge 🔁 na tabela e uma linha “Reenviado a partir de #<uuid>” no drawer de detalhes.
Próximos passos
Guia: Reenviar webhook
Fluxo completo (listar → escolher → reenviar) e o passo-a-passo do
Idempotency-KeyDetalhes do evento
Inspecione
manualResendOf, tentativas e payload antes de reenviarWas this page helpful?