API & webhooks
The API page (admin) is where you wire 42min into your own systems. It has four tabs:
- API keys — personal access tokens for server-side scripts.
- OAuth apps — register a third-party application that signs users in to 42min on their behalf.
- Webhooks — signed HTTPS callbacks that fire whenever a booking changes.
- Activity — audit log of every credential and webhook event.
This page covers the operational side — who can do what, where to click, how to rotate or revoke. For endpoint URLs, request shapes, scopes, and curl examples, see the API chapter.
Who can use this page
Only users with the Owner or Admin role can open Admin Center → API. Inside, every action is also audited — every key minted, scope changed, secret rotated, and webhook delivery shows up in the Activity log.
API keys (personal access tokens)
PATs are bearer tokens that act as the user who created them. Use them for server-side scripts and internal integrations — anywhere the caller is you.
For the full token format, curl examples, and scope reference, see Authentication → Personal access tokens and Scopes.
Mint a key
- Open API keys and click New API key.
- Give it a name unique to the account (case-insensitive).
-
Pick the scopes it should
hold. Start narrow — read-only scopes
(
user:read,bookings:read,slots:read) are enough for most reporting jobs. - Optionally set an expiry — 42 / 90 / 180 / 365 days, or never.
- Save. 42min shows the token once — copy it immediately. After that the dashboard only ever displays the last four characters.
Limits:
- 42 active keys per account.
- Each key belongs to the user who created it. If that user is removed from the account, their keys stop working.
Edit, rotate, and revoke
From the ⋯ menu on a row:
- Edit scopes — narrow or expand the key's scopes. Adding scopes is a sensitive change and 42min asks you to re-enter your account password before applying it. Narrowing scopes doesn't require the password.
- Rotate secret — issues a new token under the same id. The old token is revoked immediately. Update the secret in your script before the new one starts being used.
-
Revoke — kills the token. Subsequent calls
return
401 token_revoked.
Expired keys return 401 token_expired. Both
events are recorded in the
Activity
log.
OAuth apps
Register an OAuth app when you're building a third-party product that other 42min users install to give your app access to their account — every user gets their own consent screen and can revoke independently.
For the full authorize → consent → token → refresh flow with PKCE and reuse detection, see Authentication → OAuth 2.1 + PKCE.
Register an app
- Open OAuth apps and click New OAuth app.
-
Fill in:
- Name — shown to users on the consent screen.
- Description — optional, also shown on the consent screen.
-
App type:
-
Confidential — server-side app that
can keep a client secret. Authenticates with
client_secret_basicorclient_secret_post. -
Public — browser or mobile app.
Uses PKCE only;
token_endpoint_auth_method=none.
-
Confidential — server-side app that
can keep a client secret. Authenticates with
-
Redirect URIs — one per line, exact
match at authorize time. Must be
https://, excepthttp://localhostandhttp://127.0.0.1for development. Up to 20. - Allowed origins (public apps only) — for browser-based clients.
- Allowed scopes — the superset the app can ever request. Per-grant scopes must be a subset of this list.
-
Save. 42min returns:
-
client_id—42min_<24 chars>, not a secret. -
client_secret—42min_cs_<48 chars>, shown once (confidential apps only). Store it immediately.
-
Limits:
- 10 active OAuth apps per account.
Dynamically-registered clients (via the RFC 7591
/v1/oauth/register endpoint) are tagged with a
DCR badge in the table. DCR is disabled on
the hosted api.42min.us deployment — register
apps through this page.
Edit, rotate, and revoke
From the ⋯ menu on a row:
-
Edit — change name, description, redirect
URIs, allowed origins, and allowed scopes. Tightening
allowed_scopesdoes not retroactively shrink existing tokens — revoke them if you need that. -
Rotate secret (confidential apps only) —
issues a new
client_secretand revokes the old one immediately. Existing access/refresh tokens are unaffected; only the token endpoint requires the new secret. - Revoke — disables the app. All outstanding access and refresh tokens stop working.
Webhooks
A webhook is a URL on your server that 42min calls
(an HTTPS POST) every time one of these events
happens:
-
booking_created— someone booked a meeting. -
booking_rescheduled— a booking moved to a new time. -
booking_canceled— a booking was canceled. -
booking_no_show— a booking was marked as no-show. -
booking_updated— a booking'smetadata,responses, or attendee name was changed (viaPATCH /v1/bookings). The payload includes achanged_fieldsarray naming which of the three changed. -
event_type_updated— an event type was edited, toggled on/off, or created. The payload carries the full event-type detail (locations, questions, limits). -
event_type_deleted— an event type was deleted (payload is just its id and slug).
Each webhook gets its own signing secret (a
42min_wh_… string) so you can verify that a
request really came from 42min and wasn't forged.
Set one up
- Open Webhooks and click Add webhook.
-
Enter your endpoint URL (it must be
HTTPS — plain
http://and private/loopback addresses are rejected), an optional description, and pick which events it should receive. - Save. 42min shows the signing secret for that webhook — store it somewhere safe; you'll need it to verify requests.
- On your endpoint, verify the signature (see below) and return a 2xx status quickly. Do any slow work asynchronously so the request doesn't time out.
- Use Send test to trigger a synthetic delivery, and View logs to watch real deliveries and inspect failures.
What each delivery looks like
The request body is a JSON envelope:
{
"id": "evt_…",
"event": "booking.created",
"createdAt": "2026-05-11T14:03:00.000Z",
"apiVersion": "2026-04-01",
"data": { /* the booking */ }
}
event is the dot-notation name
(booking.created, booking.updated,
event_type.updated,
event_type.deleted, …) — note it's not spelled
the same as the underscore name you picked when subscribing.
data holds the booking for
booking.* events and the event type for
event_type.* events;
booking.updated additionally carries
data.changed_fields.
…and these headers come with it:
-
X-42min-Webhook-Signature: t=<timestamp>,v1=<signature> -
X-42min-Webhook-Event: booking.created(etc.) X-42min-Webhook-Id: <delivery id>-
X-42min-Webhook-Attempt: <attempt number>
Verifying the signature: take the
t= timestamp and the
raw request body, build the string
"<timestamp>.<raw body>", compute
HMAC-SHA256 of it with your webhook's signing
secret, hex-encode the result, and compare it to the
v1= value. Also
reject anything where the timestamp is more than ~5 minutes
old
— that stops someone replaying an old, captured request.
Delivery & retries
- If your endpoint returns a non-2xx status (or the request fails outright), 42min retries — up to 5 times — with growing gaps: 1 minute, 5 minutes, 30 minutes, 2 hours, then 12 hours.
- After 5 consecutive failures, the webhook is automatically paused — fix your endpoint, then re-enable it on the Webhooks tab.
- Every delivery attempt is kept for 30 days and then pruned. View logs shows the 50 most recent attempts for a webhook, with the status and response.
Edit, pause, rotate, delete
From the ⋯ menu on a row:
- Send test — emits a synthetic delivery so you can verify your endpoint is reachable and signing works.
- View logs — the last 50 attempts and their HTTP status.
- Edit — change the URL, description, or event list.
- Pause / Resume — stop sending without losing config.
- Rotate secret — issues a new signing secret; the old one stops being valid immediately. Update your verifier before resuming traffic.
- Delete — permanently removes the webhook and its history.
Manage webhooks over the API
Everything on this tab can also be driven programmatically
through the
/v1/webhooks
endpoints (create, list, edit, delete, rotate-secret,
send-test, list deliveries) using a PAT or OAuth token that
holds webhooks:read /
webhooks:write. That's how an installed
integration wires up its own delivery endpoint without an
admin opening this page.
One important difference: API-managed webhooks live in a
per-credential sandbox. A token only sees and
changes the webhooks it created — webhooks you add
here in the admin UI are not visible to the API, and vice
versa.
This page (the admin UI) still shows every webhook in the
account, however the hook was created. Full details and the endpoint
reference are in
API → /v1/webhooks.
Activity log
Every credential and webhook event is recorded in the Activity tab — an append-only audit feed scoped to your account. Use it when you need to answer "who did what, when, and from where".
What it records
| Category | Events |
|---|---|
| PATs |
pat.created, pat.regenerated,
pat.scopes_expanded,
pat.scopes_narrowed,
pat.updated, pat.revoked
|
| OAuth apps |
oauth_client.created,
oauth_client.updated,
oauth_client.secret_rotated,
oauth_client.dcr_registered,
oauth_client.revoked
|
| OAuth tokens |
oauth.authorization_code.issued,
oauth.authorization_code.replay_detected,
oauth.token.issued,
oauth.token.revoked,
oauth.refresh_token.reuse_detected
|
| Webhooks |
webhook.created,
webhook.updated,
webhook.paused,
webhook.resumed,
webhook.secret_rotated,
webhook.tested,
webhook.deleted
|
| Auto-revocation |
token.auto_revoked_on_leak — a PAT or OAuth
token was found in a public source (e.g. a GitHub
commit) and auto-revoked.
|
Webhooks created through the
API are audited under the
parallel api.webhook.* names (e.g.
api.webhook.created) so you can tell admin-UI
actions from credential-driven ones.
Each row carries the event type, the resource it touched, the actor's IP, and the timestamp.
Filter and paginate
- Pick one event type from the dropdown to filter, or leave it blank for everything.
- The list loads 50 at a time; Load more fetches the next page.
When to use it
- Confirm a key really was rotated when someone said they did it.
-
Investigate an unexpected
oauth.refresh_token.reuse_detected— that means a refresh token was used twice, which kills the entire grant family. Either a client bug or a credential leak. - Trace which IPs are minting keys.
When to use which
- Your own script that is you → PAT.
- Your product that other 42min users install → OAuth app.
- "Tell me when a booking changes" → Webhook.
- "I want our scheduler to post into Slack/CRM in real time" → Webhook, or — for Pipedrive specifically — the purpose-built Pipedrive integration.
- "I want reminders or follow-ups for invitees and hosts" → not a webhook, use workflows.
Common pitfalls
- Lost the PAT or client secret. Both are shown only once at creation. If you've lost it, rotate the credential — the old one will stop working but a new value is shown for you to capture.
-
Webhook endpoint isn't HTTPS (or is internal).
42min only calls public HTTPS URLs —
http://,localhost, and private IP ranges are refused when you add the webhook. -
Not verifying the signature. An unverified
endpoint will accept anything that finds the URL — always
check
X-42min-Webhook-Signatureagainst your secret, and reject old timestamps. -
Verifying against a re-parsed body. Compute
the HMAC over the raw bytes you received,
not over
JSON.stringify(parsedBody)— re-serializing can change whitespace or key order and break the comparison. - Slow endpoint → retries pile up. If you don't answer quickly with a 2xx, 42min treats it as a failure and retries; do heavy work after you've acknowledged.
- Webhook went quiet. It may have hit 5 consecutive failures and auto-paused — check View logs, fix the endpoint, and re-enable it.
- Adding a scope to a PAT silently failed. Expanding scopes requires re-entering your account password. The save button stays disabled until you do.
Last updated May 19, 2026.