PosthasteDocsGet an API key

Reference

API reference

Every endpoint the API serves — 103 of them — with what each one needs and the exact body it accepts. Generated from the running server, so it describes the API you are calling rather than the one somebody remembered to document.

Base URL https://api.posthastemail.dev. The machine-readable document is at /v1/openapi.json, and there is a Postman collection whose example bodies are tested against the same schemas the server validates with.

Account

PATCH/v1/accountdashboard session only

Rename the account

Requires a signed-in person with the **admin** role or higher — rename the account. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

FieldTypeNotes
namestring required
GET/v1/account/deletiondashboard session only

Status of a deletion request

Requires a signed-in session, acting on your own record — see whether a deletion is scheduled. Deliberately not role-gated, because the row being changed is the caller’s own.

POST/v1/account/deletiondashboard session only

Request account deletion

Right to erasure. Scheduled rather than immediate, so it can be cancelled.

Requires a signed-in person with the **owner** role or higher — delete the account. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

DELETE/v1/account/deletiondashboard session only

Cancel a deletion request

Requires a signed-in person with the **owner** role or higher — cancel a scheduled deletion. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

GET/v1/account/verifyaccount:read

Whether the delivery record is intact

The same verdict as `/v1/audit/verify`, in the older, narrower shape: `intact`, `brokenAt`, `problem`. Reachable with `account:read` because it returns no part of the log itself.

Requires an API key with `account:read`, or a signed-in session.

GET/v1/meaccount:read

Your account, plan and current sending allowance

Requires an API key with `account:read`, or a signed-in session.

PATCH/v1/profiledashboard session only

Change your own name

Requires a signed-in session, acting on your own record — set your own name. Deliberately not role-gated, because the row being changed is the caller’s own.

FieldTypeNotes
namestring required
GET/v1/usageaccount:read

Current usage against your allowance

Requires an API key with `account:read`, or a signed-in session.

Alerts

GET/v1/alerts/eventsalerts:read

What has fired, and where it went

Newest first, keyset-paginated. Each row carries the value and the threshold AS THEY STOOD, not as they are now, plus which channels the notice was delivered on — so "you never told us" has an answer that survives somebody editing the rule afterwards.

Requires an API key with `alerts:read`, or a signed-in session.

GET/v1/alerts/rulesalerts:read

List alert rules

Every threshold on the account, with the live firing state and the last measurement. Also returns the vocabulary — the available kinds, their units and their defaults — so a client never has to hard-code them.

Requires an API key with `alerts:read`, or a signed-in session.

POST/v1/alerts/rulesalerts:write

Create an alert rule

With a body, creates one rule. With NO body, creates the default set for every kind — which is the "switch alerting on" call, because picking four thresholds before you have ever seen one fire is guesswork.

One rule per kind: a second one answers 409. Two rules watching one signal would mean two emails about it, which is the failure alerting exists to avoid.

`threshold` is a fraction for the rate kinds (`0.003` is 0.3%) and a count for `dns_drift`. It is refused above the point at which the account would be suspended for the same numbers, since an alert that can only arrive after the suspension is not an alert.

Requires an API key with `alerts:write`, or a signed-in session.

FieldTypeNotes
kind"complaint_rate" | "bounce_rate" | "quota_usage" | "dns_drift" required
thresholdnumber required
windowDaysinteger optional
cooldownMinutesinteger optional
notifyEmailboolean optional
notifyWebhookboolean optional
enabledboolean optional
PATCH/v1/alerts/rules/{id}alerts:write

Change a threshold, a channel, or switch a rule off

Editing a rule never re-arms it. An alert that is currently firing stays firing, and raising the threshold while it is open is not a way to be told about it a second time.

Requires an API key with `alerts:write`, or a signed-in session.

FieldTypeNotes
thresholdnumber optional
windowDaysinteger optional
cooldownMinutesinteger optional
notifyEmailboolean optional
notifyWebhookboolean optional
enabledboolean optional
DELETE/v1/alerts/rules/{id}alerts:write

Stop watching a signal

Requires an API key with `alerts:write`, or a signed-in session.

API keys

GET/v1/api-keysaccount:read

List API keys

Requires an API key with `account:read`, or a signed-in session.

POST/v1/api-keysdashboard session only

Mint an API key

The secret is returned once and never again.

Requires a signed-in person with the **admin** role or higher — mint an API key. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

FieldTypeNotes
namestring required
scopesstring[] required
DELETE/v1/api-keys/{id}dashboard session only

Revoke an API key

Requires a signed-in person with the **admin** role or higher — revoke an API key. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

Audit

GET/v1/audit/eventsmessages:read

Page the account audit log

The append-only, hash-chained record of everything that has happened to this account’s mail, newest first. Each entry carries its own `hash` and `prevHash`, so a single row can be checked without downloading the whole log.

Deliberately does NOT verify the chain: verification replays the entire history, and doing that per page would make paging cost more the longer you have been a customer. Use `/v1/audit/verify` for the verdict.

Requires an API key with `messages:read`, or a signed-in session.

ParameterTypeNotes
limitinteger optional
beforeinteger optional
typestring optional
fromstring optional
untilstring optional
GET/v1/audit/exportmessages:read

Export the audit log as a file

Streams the whole chain as newline-delimited JSON, oldest first, with a header record describing how the hash is constructed and a trailer record carrying the event count and the verdict.

`payload` is the exact text the database hashed and `occurredAt` the exact timestamp string. Hash them as given — re-serialising the parsed JSON changes the bytes and fails verification on an untouched record.

A file with no trailer record is INCOMPLETE. The response status is sent before the last row is read, so a failure mid-transfer can only truncate the download; the trailer is how you tell a whole export from half of one.

Requires an API key with `messages:read`, or a signed-in session.

ParameterTypeNotes
fromstring optional
untilstring optional
GET/v1/audit/verifymessages:read

Prove the audit chain is intact

Replays every event on the account, in order, and reports the first break by sequence number. Answers 200 whether or not the record holds — a broken chain is evidence, not a server fault, and returning 5xx would make it look like a transient error worth retrying.

`purgedThroughSeq` is non-zero when the oldest events have aged out of your plan’s retention window through the audited purge path. That is why a chain may legitimately start above 1.

Requires an API key with `messages:read`, or a signed-in session.

Auth

POST/v1/auth/2fa/disabledashboard session only

Disable TOTP

Requires a signed-in session, acting on your own record — remove your own authenticator. Deliberately not role-gated, because the row being changed is the caller’s own.

POST/v1/auth/2fa/enabledashboard session only

Enable TOTP

Requires a signed-in session, acting on your own record — enrol your own authenticator. Deliberately not role-gated, because the row being changed is the caller’s own.

POST/v1/auth/2fa/setupdashboard session only

Begin TOTP enrolment

Requires a signed-in session, acting on your own record — enrol your own authenticator. Deliberately not role-gated, because the row being changed is the caller’s own.

GET/v1/auth/google/callback

Google sign-in callback

No authentication: is how a session is obtained.

GET/v1/auth/google/nonce

Nonce for Google One Tap

No authentication: is how a session is obtained.

POST/v1/auth/google/one-tap

Sign in with a Google One Tap credential

No authentication: is how a session is obtained.

GET/v1/auth/google/start

Begin Google sign-in

No authentication: is how a session is obtained.

POST/v1/auth/login

Sign in

No authentication: is how a session is obtained.

FieldTypeNotes
emailstring required
passwordstring required
codestring optional
POST/v1/auth/logout

Sign out

No authentication: must work even with a dead session.

GET/v1/auth/me

Who am I

How the dashboard learns its auth state on boot; no token is readable from JavaScript.

No authentication: answers "am I signed in" for the dashboard on boot.

GET/v1/auth/passkeysdashboard session only

List your registered passkeys

Requires a signed-in session, acting on your own record — list your own passkeys. Deliberately not role-gated, because the row being changed is the caller’s own.

DELETE/v1/auth/passkeys/{id}dashboard session only

Remove a passkey

Requires a signed-in session, acting on your own record — remove your own passkey. Deliberately not role-gated, because the row being changed is the caller’s own.

POST/v1/auth/passkeys/login/options

Begin passkey sign-in

No authentication: is how a session is obtained.

POST/v1/auth/passkeys/login/verify

Complete passkey sign-in

No authentication: is how a session is obtained.

POST/v1/auth/passkeys/register/optionsdashboard session only

Begin registering a passkey

Requires a signed-in session, acting on your own record — add your own passkey. Deliberately not role-gated, because the row being changed is the caller’s own.

POST/v1/auth/passkeys/register/verifydashboard session only

Finish registering a passkey

Requires a signed-in session, acting on your own record — add your own passkey. Deliberately not role-gated, because the row being changed is the caller’s own.

POST/v1/auth/password/changedashboard session only

Change your password

Requires a signed-in session, acting on your own record — change your own password. Deliberately not role-gated, because the row being changed is the caller’s own.

POST/v1/auth/password/forgot

Request a password reset

Answers the same way whether or not the address is known, so it cannot be used to test which addresses exist.

No authentication: is reached by somebody who has by definition failed to sign in.

POST/v1/auth/password/reset

Set a new password with a reset token

No header credential. A single-use token in the request body IS the credential, and it is reached from a mailbox.

GET/v1/auth/sessionsdashboard session only

List your active sessions

Requires a signed-in session, acting on your own record — list your own sessions. Deliberately not role-gated, because the row being changed is the caller’s own.

POST/v1/auth/sessions/revoke-othersdashboard session only

Sign out everywhere else

Requires a signed-in session, acting on your own record — sign your other devices out. Deliberately not role-gated, because the row being changed is the caller’s own.

POST/v1/auth/signup

Create an account

No authentication: creates the first account.

FieldTypeNotes
emailstring required
passwordstring required
accountNamestring optional
POST/v1/auth/verify-email

Verify an email address

No header credential. A single-use token in the request body IS the credential, and it is reached from a mailbox.

POST/v1/auth/verify-email/senddashboard session only

Resend the verification email

Requires a signed-in session, acting on your own record — resend your own confirmation. Deliberately not role-gated, because the row being changed is the caller’s own.

Billing

GET/v1/billingbilling:read or account:read

Subscription and plan

Requires an API key with `billing:read` or `account:read`, or a signed-in session.

POST/v1/billing/{provider}/webhook

Payment provider webhook

Authenticated by the provider signature over the RAW body, so it cannot be re-signed from a parsed copy.

No header credential. The caller is a payment or mail provider and is authenticated by its signature over the RAW request body — so this operation cannot be re-signed from a parsed copy.

POST/v1/billing/canceldashboard session only

Cancel the subscription at period end

Requires a signed-in person with the **admin** role or higher — cancel the plan. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

POST/v1/billing/checkoutdashboard session only

Start a checkout

Requires a signed-in person with the **admin** role or higher — start a checkout. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

FieldTypeNotes
planstring required
interval"month" | "year" optional
profileobject required
POST/v1/billing/checkout/abandondashboard session only

Abandon a checkout in progress

Requires a signed-in person with the **admin** role or higher — abandon a checkout. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

GET/v1/billing/historybilling:read or account:read

Billing history

Requires an API key with `billing:read` or `account:read`, or a signed-in session.

GET/v1/billing/invoicesbilling:read or account:read

List invoices

Requires an API key with `billing:read` or `account:read` (checked via `canReadBilling`), or a signed-in session.

GET/v1/billing/invoices/{id}billing:read or account:read

Download an invoice

Requires an API key with `billing:read` or `account:read` (checked via `canReadBilling`), or a signed-in session.

POST/v1/billing/pausedashboard session only

Pause the subscription

Requires a signed-in person with the **admin** role or higher — pause the plan. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

PATCH/v1/billing/profiledashboard session only

Set the legal name and tax id printed on invoices

Requires a signed-in person with the **admin** role or higher — change the billing details. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

POST/v1/billing/resumedashboard session only

Resume a paused subscription

Requires a signed-in person with the **admin** role or higher — resume the plan. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

Deliverability

GET/v1/analytics/deliveryanalytics:read

Delivery rate and time to inbox, by receiving domain or by tag

Answers "is Outlook slower than Gmail for our mail". Returns the delivery rate and the p50/p95 time to inbox for each receiving domain, or for each of your own tags, over a window you choose.

Time to inbox is measured between two events on the message: `accepted`, when it entered the delivery queue, and `delivered`, when the receiving mail server accepted it. It does not include what that server does afterwards, which no sender can observe.

A rate with nothing settled behind it and a percentile with no delivered message behind it are both `null`, never `0`. Every row carries the number of messages its percentiles were computed from.

Requires an API key with `analytics:read`, or a signed-in session.

ParameterTypeNotes
daysinteger optional
groupBystring optional
streamstring optional
tagstring optional
limitinteger optional
cursorstring optional
GET/v1/analytics/dmarcanalytics:read

Who is sending as your domains, and whether it aligns

Summarises the DMARC aggregate reports receiving providers send back about your domains, grouped by the IP that sent the mail and ranked by volume.

`messages` is the volume the reporters accounted for, summed from each report row's own count — not a number of rows, since a single row can stand for millions of messages. A message counts as aligned when SPF **or** DKIM aligned with the From domain, which is what DMARC itself requires; a mechanism that passed for some unrelated domain does not count.

A source with volume and no alignment is either a legitimate sender you have forgotten about or somebody spoofing you. The two are indistinguishable from here, so this reports what the receivers observed and leaves that judgement to you.

`alignmentRate` is `null` rather than `0` when no reports have arrived yet, because "nothing reported" and "everything failed" are opposite situations.

Requires an API key with `analytics:read`, or a signed-in session.

ParameterTypeNotes
daysinteger optional
domainstring optional

Domains

DELETE/v1/account/cloudflaredomains:write

Disconnect Cloudflare

Requires an API key with `domains:write`, or a signed-in session.

GET/v1/domainsdomains:read

List sending domains

Requires an API key with `domains:read`, or a signed-in session.

POST/v1/domainsdomains:write

Add a sending domain

Returns the DNS records to publish. Mail cannot be sent until it verifies.

Requires an API key with `domains:write`, or a signed-in session.

FieldTypeNotes
namestring required
DELETE/v1/domains/{id}domains:write

Remove a domain

Requires an API key with `domains:write`, or a signed-in session.

POST/v1/domains/{id}/cloudflaredomains:write

Publish the records via a connected Cloudflare account

Requires an API key with `domains:write`, or a signed-in session.

GET/v1/domains/{id}/setupdomains:read

The DNS records to publish

Requires an API key with `domains:read`, or a signed-in session.

POST/v1/domains/{id}/verifydomains:write

Check the DNS records now

Requires an API key with `domains:write`, or a signed-in session.

Emails

POST/v1/emailsemails:send

Send an email

Accepts a message, stores it durably, and queues it for delivery. Returns 202 with the message id — acceptance is not delivery, and the delivery outcome arrives on the webhook or in the message log.

Supply `html`/`text`, or a `template` with `variables`. A missing required template variable is a refusal, not a blank: rendering fails and nothing is sent.

Requires an API key with `emails:send`, or a signed-in session.

FieldTypeNotes
fromstring required
tostring | string[] required
ccstring[] optional
bccstring[] optional
subjectstring optional
textstring optional
htmlstring optional
replyTostring optional
headersobject optional
listUnsubscribestring optional
streamstring optional
templatestring optional
templateVersioninteger optional
variablesobject optional
tagsstring[] optional
metadataobject optional
idempotencyKeystring optional
scheduledAtstring optional
attachmentsobject[] optional
DELETE/v1/emails/{id}/scheduleemails:send

Cancel a scheduled message

Requires an API key with `emails:send`, or a signed-in session.

POST/v1/emails/batchemails:send

Send up to 100 emails in one call

Partial success is the contract: each item succeeds or fails on its own and one bad recipient never fails the batch. Each item commits independently, so an accepted message stays accepted whatever happens to the rest.

Requires an API key with `emails:send`, or a signed-in session.

FieldTypeNotes
messagesobject[] required

Inbound

GET/v1/inbound/addressesdomains:read

List inbound addresses

Requires an API key with `domains:read`, or a signed-in session.

POST/v1/inbound/addressesdomains:write

Create an inbound address

Requires an API key with `domains:write`, or a signed-in session.

FieldTypeNotes
addressstring required
labelstring optional
DELETE/v1/inbound/addresses/{id}domains:write

Delete an inbound address

Requires an API key with `domains:write`, or a signed-in session.

GET/v1/inbound/messagesmessages:read

List received messages

Requires an API key with `messages:read`, or a signed-in session.

GET/v1/inbound/messages/{id}messages:read

Fetch a received message

HTML is sanitised on the way out, without exception.

Requires an API key with `messages:read`, or a signed-in session.

DELETE/v1/inbound/messages/{id}domains:write

Delete a received message

Requires an API key with `domains:write`, or a signed-in session.

Messages

GET/v1/messagesmessages:read

List messages

Filterable by status, tag, stream, recipient domain, metadata and date. Repeated `tag` parameters are ANDed.

Requires an API key with `messages:read`, or a signed-in session.

ParameterTypeNotes
limitinteger optional
beforestring optional
statusstring optional
tostring optional
searchstring optional
domainstring optional
streamstring optional
tagstring optional
metadatastring optional
fromstring optional
untilstring optional
GET/v1/messages/{id}messages:read

Fetch one message

Requires an API key with `messages:read`, or a signed-in session.

GET/v1/messages/{id}/attachments/{attachmentId}messages:read

Download an attachment

Served `Content-Disposition: attachment` — never rendered inline on our origin, whatever the declared content type.

Requires an API key with `messages:read`, or a signed-in session.

GET/v1/messages/tailmessages:read

Stream message events as they happen

A Server-Sent Events stream of the same events the message log holds, delivered as they are written. Nothing polls: the connection is idle until an event lands.

Each `message` event carries the account `seq` as its SSE id. Reconnect with `Last-Event-ID` (browsers send it automatically) or `?after=<seq>` and everything after that position is replayed, so a dropped connection loses nothing.

A `ready` event opens the stream, `heartbeat` arrives every 15 seconds, and `bye` says why we closed. The stream is closed after 15 minutes with no message event; reconnect and resume. Five concurrent tails per account — a sixth is refused with `too_many_streams`.

Requires an API key with `messages:read`, or a signed-in session.

ParameterTypeNotes
statusstring optional
streamstring optional
tagstring optional
replayinteger optional
afterinteger optional
GET/v1/stats/messagesmessages:read

Message counts over time

Requires an API key with `messages:read`, or a signed-in session.

ParameterTypeNotes
daysinteger optional
domainstring optional
tzstring optional

Other

POST/v1/leads

Contact-form enquiry

Requires the platform account's own key: the marketing contact form.

GET/v1/openapi.json

This document

Served from the running server, so it always describes the API you are calling.

No authentication: describes only the public API, which is equally discoverable by trying it.

Streams

GET/v1/streamsstreams:read

List message streams

Requires an API key with `streams:read`, or a signed-in session.

POST/v1/streamsstreams:write

Create a message stream

Streams separate suppression scope and statistics, so a complaint on one stream can never suppress a password reset on another.

Requires an API key with `streams:write`, or a signed-in session.

FieldTypeNotes
slugstring required
namestring required

Sub-accounts

GET/v1/sub-accountsaccount:read

List the accounts you pay for

Returns what a payer is entitled to know — name, status and volume this month. Never the sub-account’s mail, domains or suppressions: the billing relationship is not a window into its data.

Requires an API key with `account:read`, or a signed-in session.

POST/v1/sub-accountsdashboard session only

Create a sub-account

A fully isolated account with its own domains, keys and suppression list, billed to you and sharing your monthly allowance. It inherits your plan and cannot hold a subscription of its own.

Requires a signed-in person with the **admin** role or higher — add an account to the bill. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

FieldTypeNotes
namestring required
GET/v1/sub-accounts/{id}account:read

One sub-account’s standing

Requires an API key with `account:read`, or a signed-in session.

Suppressions

GET/v1/suppressionssuppressions:read

List suppressed addresses

Every entry carries its cause: the reason, the receiving server’s own words, its status code, and the message whose bounce or complaint caused it. An entry added by hand has no causing message, and neither has one whose message has since aged out of retention.

Requires an API key with `suppressions:read`, or a signed-in session.

ParameterTypeNotes
limitinteger optional
beforestring optional
searchstring optional
reasonstring optional
POST/v1/suppressionssuppressions:write

Suppress an address

Requires an API key with `suppressions:write`, or a signed-in session.

FieldTypeNotes
addressstring required
reasonstring optional
streamstring optional
DELETE/v1/suppressions/{address}suppressions:write

Remove a suppression

Removes a `manual` or `unsubscribe` entry. A hard bounce cannot be removed this way (422 suppression_hard_bounce): re-sending to an address that does not exist is what costs a sender its reputation, and a genuinely stale one is lifted by support after review. A complaint or spam trap can never be removed at all (422 suppression_protected).

Requires an API key with `suppressions:write`, or a signed-in session.

Team

GET/v1/teamteam:read

List members and pending invitations

Requires an API key with `team:read`, or a signed-in session.

PATCH/v1/team/{id}dashboard session only

Change a member's role

The person is signed out everywhere, because their permissions changed.

Requires a signed-in person with the **admin** role or higher — change a colleague's role. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

FieldTypeNotes
role"owner" | "admin" | "member" | "viewer" required
DELETE/v1/team/{id}dashboard session only

Remove somebody from the account

The last owner cannot be removed — an account with no owner has nobody who can administer it.

Requires a signed-in person with the **admin** role or higher — remove a colleague. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

POST/v1/team/invitesdashboard session only

Invite somebody

Requires a signed-in person with the **admin** role or higher — invite a colleague. NOT reachable with an API key: this is an action where a leaked server-side credential would be catastrophic.

FieldTypeNotes
emailstring required
role"owner" | "admin" | "member" | "viewer" required
POST/v1/team/invites/accept

Accept an invitation

Sets the password and verifies the address. Does not sign you in.

No header credential. A single-use token in the request body IS the credential, and it is reached from a mailbox.

FieldTypeNotes
tokenstring required
passwordstring required

Templates

GET/v1/templatestemplates:read

List templates

Requires an API key with `templates:read`, or a signed-in session.

POST/v1/templatestemplates:write

Create a template

Requires an API key with `templates:write`, or a signed-in session.

FieldTypeNotes
subjectstring optional
htmlstring optional
textstring optional
variablesobject[] optional
GET/v1/templates/{id}templates:read

Fetch a template

Requires an API key with `templates:read`, or a signed-in session.

PATCH/v1/templates/{id}templates:write

Edit a template, publishing a new version

A published version is immutable. Editing content publishes the next version and leaves the previous one byte-identical, so a send can always be traced to the exact content that went out.

Requires an API key with `templates:write`, or a signed-in session.

FieldTypeNotes
subjectstring optional
htmlstring optional
textstring optional
variablesobject[] optional
DELETE/v1/templates/{id}templates:write

Delete a template

Requires an API key with `templates:write`, or a signed-in session.

POST/v1/templates/{id}/previewtemplates:read

Render a template without sending

Returns the rendered HTML and text for sample variables, and reports the same refusals a send would — so a preview cannot pass where the send fails.

Requires an API key with `templates:read`, or a signed-in session.

FieldTypeNotes
versioninteger optional
variablesobject optional
GET/v1/templates/{id}/versionstemplates:read

List template versions

Requires an API key with `templates:read`, or a signed-in session.

POST/v1/templates/previewtemplates:read

Render content without saving it

Renders what you supply rather than what you have published, so an editor can show a template before it exists. Reports the same refusals and the same lint a send would, and stores nothing.

Requires an API key with `templates:read`, or a signed-in session.

FieldTypeNotes
subjectstring optional
htmlstring optional
textstring optional
variablesobject[] optional
valuesobject optional

Webhooks

GET/v1/webhookswebhooks:read

List webhook endpoints

Requires an API key with `webhooks:read`, or a signed-in session.

POST/v1/webhookswebhooks:write

Create a webhook endpoint

Deliveries are signed; verify the signature before trusting a payload. Retried with backoff and idempotent on redelivery.

Requires an API key with `webhooks:write`, or a signed-in session.

FieldTypeNotes
urlstring required
eventTypesstring[] optional
DELETE/v1/webhooks/{id}webhooks:write

Delete a webhook endpoint

Requires an API key with `webhooks:write`, or a signed-in session.

NextErrorsEvery error type the API returns, what causes it, and whether to retry.