Webhook endpoints
Register the endpoint your webhooks go to. You have one endpoint for now. Gave generates its signing secret and shows it once, when the endpoint is created or its secret is rotated: store it straight away.
Register your endpoint
Give it an ID of your choice and an https URL with a public host name: no IP address, local or internal name, credentials or fragment. Gave doesn't follow redirects: a 3xx answer is a failed delivery, retried.
curl https://api.sandbox.gave.sh/v1/webhook-endpoints \
-H "x-api-key: $GAVE_API_KEY" \
-H "content-type: application/json" \
-d @create-endpoint.json{ "id": "main", "url": "https://hooks.acme.example/gave" }It answers 201 Created, with the signing secret:
{
"endpoint": { "id": "main", "url": "https://hooks.acme.example/gave", "createdAt": "2026-10-11T09:00:00.000Z" },
"secret": "gave_whsec_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"duplicate": false
}The same request again answers duplicate: true, without the secret; the same ID with another URL is a 409, and a second endpoint a 422. Deliveries start within a minute.
Change its URL
curl -X PATCH https://api.sandbox.gave.sh/v1/webhook-endpoints/main \
-H "x-api-key: $GAVE_API_KEY" \
-H "content-type: application/json" \
-d '{ "url": "https://hooks.acme.example/gave/v2" }'The secret doesn't change. Deliveries follow within a minute.
Rotate its secret
curl -X POST https://api.sandbox.gave.sh/v1/webhook-endpoints/main/rotate-secret \
-H "x-api-key: $GAVE_API_KEY"{
"endpoint": {
"id": "main",
"url": "https://hooks.acme.example/gave",
"createdAt": "2026-10-11T09:00:00.000Z",
"previousSecretExpiresAt": "2026-10-12T10:00:00.000Z"
},
"secret": "gave_whsec_fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
}The new secret signs deliveries within a minute. Each secret it replaces keeps signing for 24 hours from its rotation, up to four of them, until previousSecretExpiresAt for the last: the x-gave-signature header carries one v1 per secret. Accept any you hold while you deploy the new one; the signature check does. Each call makes a new secret: if a rotation's answer is lost, rotate again, and the secret you still use keeps working. To drop a leaked secret, rotate five times: the leaked one goes.
Read it, delete it
GET /v1/webhook-endpoints lists your endpoints, and GET /v1/webhook-endpoints/{id} reads one; neither shows the secret. DELETE /v1/webhook-endpoints/{id} deletes it: deliveries stop within a minute. Without an endpoint, Gave delivers nothing, and your users' state stays readable through the API.