Skip to main content
Hermes tells your system when a permanent change happens. A payout gets to its terminal state, a pay-in credits your balance, or your balance goes below its floor. For each change, Hermes sends an event to your webhook endpoint with an HTTP POST.

Register an endpoint

An org admin registers the endpoint in the Hermes portal, under Integration → Webhook endpoint. Each org has one HTTPS URL and one active endpoint. When you register an endpoint, Hermes makes a signing secret (whsec_…). Hermes shows the secret one time only. Keep the secret with your API key. If you replace the endpoint, Hermes makes a new secret. Deliveries that are already in progress continue with the old secret. So while you change the secret, verify each delivery against both secrets.

The event wrapper

Each delivery is a JSON POST with the same wrapper:
  • id — the key that you use to remove duplicates. Hermes delivers each event one time or more. The same event can arrive more than one time, and events can arrive in a different sequence. Process each id one time only, and ignore the repeats.
  • balance — a copy of your balance from the time when Hermes prepared the event. Do not calculate a balance from webhooks, because events can arrive in a different sequence. GET /balance is the correct source.
  • data — the resource, with the same bytes as the equivalent /v1 read endpoint.

Event list

An org admin sets the floor for balance.low in the Hermes portal, under Integration → Balance floor. You can change the floor at any time.

Verify a signature

Each delivery has a Signature header. The header is the HMAC-SHA256 of the exact raw request body, with your signing secret as the key, in hexadecimal. There are no timestamp headers, and there is nothing more to put in order. Sign the bytes that you received. Then compare the two values in constant time.
Calculate the HMAC over the raw body bytes, before you parse the JSON. If you parse the JSON and write it again, the field sequence or the format changes. The signature then never agrees.
Node.js (Express)
While you change the secret, verify against the old secret and the new secret. Accept the delivery if one of the two agrees.

Compare your result against ours

The Hermes portal keeps a record of each delivery, under Portal → Deliveries. Open a row to see the exact bytes that Hermes sent, and the signature that Hermes calculated over those bytes. Use the screen when your signature does not agree. It shows you which of the two values is different, and it shows the bytes that your code must sign.
A reversal needs your attention, and your balance can be late. A payout.reversed or a collection.reversed event tells you that the provider took back money that already moved. Use the event as the correct signal, and let your balance catch up. A person in Jenzy operations posts the correction. For the full detail, see Payouts → How to learn the result and Pay-ins → Reversals.

Delivery rules

  • Only a 2xx response counts as a delivery. A redirect is a failure, and Hermes never follows one. Respond in less than 10 seconds, and do the real work after the response.
  • Hermes tries a failed delivery 5 more times across about 6 hours. The first tries are close together. Each try sends the same bytes, because Hermes made a copy of the payload at the time of the event. So the signature stays valid across all the tries.
  • After the last failed try, Hermes puts the delivery in a dead-letter queue and tells Jenzy operations. Hermes never sends it again automatically.
  • Portal → Deliveries lists each try against each of your endpoints, newest first.
  • If you missed events during an outage, ask Jenzy for a new delivery. Until then, compare your records against GET /payouts. A poll and a webhook give the same data, so the list endpoint is always a way to catch up.