heruAPI
Webhooks

Create a webhook subscription

BuildingIn development for the v1 API. The contract is set; the route is not served yet.

POST
/webhooks

Registers a URL to receive the events listed, signed with a secret of its own. The answer carries secret once: store it, it is never shown again. Retrying with the same Idempotency-Key and body returns the same subscription, secret included. A company can hold up to 10 subscriptions. See the Webhooks guide for signature verification, idempotency and retries.

Needs the webhooks:write scope.

Authorization

oauth2 webhooks:write
headerAuthorizationBearer <token>

OAuth 2.0 client credentials. Exchange your client_id and client_secret at /oauth/token of the environment for a bearer token valid for one hour. The playground of every operation asks for your own client and keeps it in your browser tab only.

Scope: webhooks:write

Header parameters

Idempotency-Key*string

Unique per operation. Retrying with the same key returns the original result for 24 hours.

Lengthlength <= 255

Request body

application/json
  1. body
url*string

Absolute https URL heru POSTs to: a public host, port 443 or 1024 and above, no credentials and no fragment. heru does not follow redirects.

Formaturi
Lengthlength <= 2048
event_types*array<string>

Types from the WebhookEvent.type enum, or * for every current and future type. If * is present only * is kept.

Items1 <= items <= 20
merchant_ids?array<>

Only events of these merchants. Empty or absent means every merchant of the company.

Itemsitems <= 100
description?string
Lengthlength <= 500
headers?array<>

Extra headers sent on every delivery, such as a token your gateway expects.

Itemsitems <= 5

Response body

The subscription is active. Store secret: it signs every delivery and is never shown again.

application/json
  1. response
id*string
Match^whk_[0-7][0-9a-hjkmnp-tv-z]{25}$
url*string
Formaturi
description*string
event_types*array<string>
merchant_ids*array<>
status*string

active delivers; paused you set it and deliveries wait; disabled heru set it (see disabled_reason) and deliveries wait until you send status: active.

Value in"active""paused""disabled"
disabled_reason*|null
disabled_at*|null
headers*array<>
secret?string

Only in the answer of POST /webhooks and POST /webhooks/{id}/secret. Store it: it is never shown again.

Match^whsec_[A-Za-z0-9_-]{43}$
secret_last4*string
secret_rotating_until*|null
consecutive_failures*integer

Failed deliveries in a row. A 2xx resets it to zero.

failing_since*|null
environment*string
Value in"sandbox""production"
created_at*string
Formatdate-time
updated_at*string
Formatdate-time
deliveries*

Where the delivery log of this subscription is.

curl -X POST 'https://api.dev.b2b.heru.app/v1/webhooks' \  -H 'Idempotency-Key: try-it-0001' \  -H 'Content-Type: application/json' \  -d '{  "url": "https://partner.example.com/heru/webhooks",  "event_types": [    "invoice.stamped",    "charge.invoiced"  ],  "merchant_ids": [    "mer_01m4ra8wsyfh3s0tr4nrq3y96j"  ],  "description": "POS production",  "headers": [    {      "name": "X-Partner-Token",      "value": "s3cr3t-token-abcd"    }  ]}'
{  "id": "whk_01m53g5zw414zt6vg08fqbacgm",  "url": "https://partner.example.com/heru/webhooks",  "description": "POS production",  "event_types": [    "invoice.stamped",    "charge.invoiced"  ],  "merchant_ids": [    "mer_01m4ra8wsyfh3s0tr4nrq3y96j"  ],  "status": "active",  "disabled_reason": null,  "disabled_at": null,  "headers": [    {      "name": "X-Partner-Token",      "value": "****abcd"    }  ],  "secret": "whsec_MfKdm7bK1VQmYzmmtzMTeUwRUOz9ozNtg_xq6WfL2Do",  "secret_last4": "L2Do",  "secret_rotating_until": null,  "consecutive_failures": 0,  "failing_since": null,  "environment": "production",  "created_at": "2026-10-25T12:00:00.000Z",  "updated_at": "2026-10-25T12:00:00.000Z",  "deliveries": {    "path": "/v1/webhooks/whk_01m53g5zw414zt6vg08fqbacgm/deliveries"  }}
© 2026 Kuarto Inc. (heru)heru.appQuestions about your integration? Contact your heru account team.