Skip to main content

Use the Lead Hero API and webhooks safely

Create an organization API key, authenticate requests, subscribe to documented events, and confirm unsupported actions before designing a custom integration.

Ü
Written by Ümit Baltacı

Create an API key, make an authenticated request, and receive signed webhooks without losing or duplicating events.

Who can do this: owners and managers. The Developer tab does not appear at all for anyone else.

Before you build against the API, check Supported integrations. If we already connect to your tool, that path is less work and less to maintain.

Create an API key

  1. Open Settings, then the Developer tab. You can link straight to it with ?tab=developer.

  2. Copy your Organization ID from the top of the API Keys card. Every API route needs it, and this is the only place it is offered with a copy button.

  3. Enter a label that says where the key will be used.

  4. Pick a Lifetime: 30 days, 6 months, 1 year, Unlimited, or Custom date.

  5. Select Create API key.

  6. Copy the key from the dialog straight away.

The API Keys card. The Organization ID sits at the top, above the key list.

The key is shown once and never again. Only its identifier and status appear afterwards. If you lose it, the only remedy is to create another and revoke the old one.

A key looks like <keyId>.<secret>, where the first half is a UUID. Only the second half is stored hashed, which is why we cannot recover it for you.

Treat a key as an owner-level credential. Keys belong to an organization, not a person, and a request made with one acts as that organization's highest-privilege active member. There is no way to give a key a smaller role.

Make a request

The base URL is https://api.leadhero.io. Send the key either way:

x-api-key: <keyId>.<secret>

Authorization: Bearer <keyId>.<secret>

A first request looks like this:

curl -H "x-api-key: <keyId>.<secret>" \
  https://api.leadhero.io/leads/<organization>

The generated reference, filtered to the routes a key can reach, is at https://api.leadhero.io/documentation/api-key.

A key only works on routes that carry the organization in the path, and only on an allowlist of those. Presented anywhere else it is ignored rather than refused, so the failure looks like bad credentials rather than a wrong route. If a request fails auth and you are sure the key is good, check the route before regenerating anything.

Creating an outbound call is blocked for API keys. This is an explicit denial, not a gap, so it will not be enabled on request.

Rate limit

120 requests per minute, counted per key, so separate keys get separate budgets. Going over returns 429 with a message saying when to retry.

Rotate a key

There is no rotate-in-place, and revoking takes effect immediately, so order matters:

  1. Create the new key.

  2. Deploy it.

  3. Confirm traffic is arriving on the new key.

  4. Revoke the old one.

Nothing reminds you when a key is about to expire. If you choose Unlimited, put the rotation in your own calendar. Custom date is useful for staging a rotation you already have a date for.

Receive webhooks

  1. In the same Developer tab, create a webhook and give it a label and a URL.

  2. Set Scope to: either a single workspace or All workspaces. A workspace-scoped webhook stays silent for everything outside it, which is worth checking first when events seem to be missing.

  3. Select Configure Events and tick what you want.

  4. Turn on the signing secret.

Events are chosen per webhook. Nothing is subscribed by default.

The signing secret is also shown only once. There is no regenerate button and no secret field on an existing webhook, so rotating one means creating a second webhook to the same URL, cutting over, then deleting the first.

Events

Event

Fires when

call.initiated

A call starts

call.answered

A call is answered

call.completed

A call ends

lead.created

A lead is created

lead.updated

A lead changes

lead.deleted

A lead is deleted

lead.status.update

A lead's status changes

enrichment.completed

An enrichment job finishes

lead.status.update is the only event with a filter. You can narrow it to specific statuses, so a webhook watching for booked stays quiet through everything else.

Verify the signature

Every signed delivery carries these headers:

Header

Contents

X-LeadHero-Signature

sha256= followed by the hex digest

X-LeadHero-Timestamp

Milliseconds since the epoch

X-LeadHero-Event

The event name

X-LeadHero-Webhook-Id

Which webhook sent it

X-LeadHero-Delivery-Id

Unique per delivery

The digest is HMAC-SHA256 over the timestamp, a full stop, and the raw request body:

sha256=HMAC_SHA256(secret, timestamp + "." + rawBody)

Sign the raw bytes, not a re-serialised object. Parsing the JSON and stringifying it again will change the body and the signature will never match, which is the usual reason a first integration fails.

Delivery, retries, and duplicates

Any 2xx counts as success. Anything else fails and is retried, up to 5 attempts, backing off exponentially from 2 seconds, with each attempt timed out at 15 seconds. Deliveries are throttled to 10 per second across the whole system.

Return 2xx only once you have durably stored the event. Acknowledging first and processing after means a crash loses the event for good, because we already counted it as delivered.

Expect the same event more than once. Retries and at-least-once delivery both cause it. Deduplicate on X-LeadHero-Delivery-Id, which is unique per delivery and stable across retries of that delivery.

When to contact support

Get in touch if:

  • Authorization fails repeatedly on a route you believe is allowed.

  • Signature verification never matches, even against the raw body.

  • Events are still missing after all retries should have run.

  • The action you need is not in the API reference.

Include the request time, the endpoint, the response status, and the delivery ID. Never include the secret or the full authorization header.

Next steps

Did this answer your question?