Webhook
Webhooks and events: everything that happens, delivered to your server, signed.
hook = noclick.Webhook.from_name("https://api.yourco.test/noclick/events", create_if_missing=True,
events=["operation.*", "human.answered"])
secret = hook.reveal_secret() # needs the webhooks:reveal scope
# in your receiver
event = noclick.Webhook.verify(request_body, request_headers, secret)
print(event.type, event.data)Every event is also kept for 30 days: noclick.Event.list(type="domain.*").
class WebhookAn endpoint on your server that receives events, signed with its secret. One created for a
user (inside asUser, or with user) receives only that user's events; your account's
own receive every event, your users' included.
- Like every live object, it also has hydrate(), refresh() and raw.
| id | string | |
| url | string | |
| events | string[] | The event types it receives; |
| enabled | boolean | |
| status | WebhookStatus |
|
| description | string | null | |
| successRate24h | number | null | The share of attempts in the last 24 hours your server answered 2xx (null if none). |
| lastFailure | JsonObject | null | The latest failed attempt: |
| userId | string | null | The user whose events it receives (null: every event). |
| createdAt | Date | null | |
| secret | string | null | The signing secret ( |
createstatic
static create(url: string, options: WebhookCreateOptions): Promise<Webhook>Start delivering events to url, an https address your server answers. secret is shown on the result this once.
The event types it receives; operation.* or * for more at once.
undefined = the ambient user (asUser), null = the account itself.
Makes a retried create safe: the same key returns the first result. Generated when omitted.
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
The new webhook. Its secret is shown this once: store it where your receiver reads it.
fromNamestatic
static fromName(
url: string,
options?: CallOptions & {
createIfMissing?: boolean;
events?: readonly string[];
description?: string;
},
): WebhookA lazy reference to the webhook delivering to url for the current (or given) user; url names
it, since a scope has one webhook per address. With createIfMissing your code is the
definition: it's created on first use with events (and description), and an existing one
whose events or description differ is updated to match. secret holds the signing secret when
this call created it; otherwise read it with revealSecret().
undefined = the ambient user (asUser), null = the account itself.
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
A webhook that loads (or is created, or brought in step with your definition) the
first time it's used. When this call created it, secret holds its signing secret;
otherwise read it with reveal_secret().
fromIdstatic
static fromId(webhookId: string, options?: CallOptions): WebhookA lazy reference to a webhook by id.
A webhook that loads the first time you read a field. Nothing is sent yet.
getstatic
static get(webhookId: string, options?: CallOptions): Promise<Webhook>Load a webhook by id now; an unknown id raises noclick.NotFound.
The webhook, loaded (without its secret).
liststatic
static list(options?: ReadOptions & { limit?: number }): Promise<Webhook[]>Your account's webhooks (or the current user's, or those userFilter covers).
Return at most this many.
Which users the read covers (user_id query), instead of acting as one (user).
undefined = the ambient user (asUser), null = the account itself.
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
Every matching webhook, newest first, fetched page by page.
listPagestatic
static listPage(options?: ReadOptions & PageOptions): Promise<Page<Webhook>>One page of webhooks; pass nextCursor back as cursor.
The next_cursor of the page before; omit it for the first page.
Return at most this many.
Which users the read covers (user_id query), instead of acting as one (user).
undefined = the ambient user (asUser), null = the account itself.
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
A page whose data holds the webhooks and whose next_cursor is None on the last page.
update
update(changes: WebhookChanges): Promise<this>Change where it delivers, what it receives, or pause it (enabled: false).
This webhook, updated.
delete
delete(): Promise<void>Delete the webhook; deliveries still retrying stop.
rotateSecret
rotateSecret(options?: { graceS?: number }): Promise<string>Replace the signing secret. For graceS (default a day, at most 7 days) each delivery is
signed with both, so deliveries keep verifying while you deploy the new one; graceS: 0 if the
old one leaked. Resolves to the new secret, shown this once (also on hook.secret).
The new secret, shown this once (also on hook.secret).
revealSecret
revealSecret(): Promise<string>Read the current signing secret, so a receiver that starts from code (or a webhook fromName
found rather than created) can verify deliveries. Needs a key with the webhooks:reveal scope,
which full access leaves out; every reveal is recorded with the key that made it.
The secret (nk_whsec_...), also on hook.secret.
test
test(eventType?): Promise<WebhookDelivery>Send a sample event of eventType now, signed like a real one, and wait up to 10 seconds for
your server's answer. It isn't retried and isn't recorded in Event.list.
"operation.succeeded"The delivery: its status (succeeded or failed), response_status and response_body.
deliveries
deliveries(
options?: {
status?: WebhookDeliveryStatus | readonly WebhookDeliveryStatus[];
event?: Event | string;
limit?: number;
},
): Promise<WebhookDelivery[]>Deliveries newest first (the last 30 days), optionally only those with status or of one event.
Return at most this many.
Every matching delivery, fetched page by page (or the first limit).
redeliver
redeliver(delivery: WebhookDelivery | string): Promise<WebhookDelivery>Send a delivery's event again now (the same event id), whatever its status.
The delivery, with this attempt counted in attempts and its outcome in status.
verifystatic
static verify(
payload: string | Uint8Array | ArrayBuffer,
headers: WebhookHeaders,
secret: string | readonly string[],
options?: { toleranceS?: number },
): Promise<Event>Check a delivery in your receiver: payload is the raw body exactly as it arrived (not parsed
and re-serialized), headers its headers and secret the webhook's, or several while you
rotate. The NoClick-Signature header is t=<unix seconds>,v1=<hex>, where the hex is
HMAC-SHA256 of "<t>.<body>" keyed with the secret; a timestamp more than toleranceS
(300) from now is refused, so a captured delivery can't be replayed. Sends nothing.
Throws WebhookSignatureError for a missing or malformed header, a stale timestamp, or no match.
300The event the body carries, ready to act on.
WebhookDelivery
interface WebhookDeliveryOne event sent (or on its way) to one webhook. status is pending (not tried yet),
retrying (an attempt failed; nextRetryAt says when the next one is), succeeded (your
server answered 2xx) or failed (three days of retries ran out). responseStatus and
responseBody (its first 4 KB) are from the latest attempt; requestBody is the JSON sent.
| id | string | |
| webhookId | string | null | |
| eventId | string | null | |
| eventType | string | null | |
| status | WebhookDeliveryStatus | |
| attempts | number | |
| responseStatus | number | null | |
| responseBody | string | null | |
| requestBody | string | null | |
| durationMs | number | null | |
| error | string | null | Why the latest attempt failed ( |
| nextRetryAt | Date | null | |
| createdAt | Date | null | |
| raw | JsonObject | The response JSON exactly as the API sent it. |
| ok | boolean | Whether your server accepted it (a 2xx). |
Event
class EventSomething that happened: an operation finished, a person answered, a domain went live.
type names it (see Event.types()) and data is the object it's about, as its own read
returns it (data.object names the kind, data.id its id). Delivered to your webhooks, and
kept for 30 days.
- Like every live object, it also has hydrate(), refresh() and raw.
| id | string | |
| type | string | What happened, like |
| data | JsonObject | The object the event is about, as its own read returns it. |
| userId | string | null | The user it happened for (null for your account's own). |
| createdAt | Date | null | |
| deliveries | WebhookDelivery[] | Where this event went: one delivery per webhook that subscribes to it. The full view carries
them ( |
fromIdstatic
static fromId(eventId: string, options?: CallOptions): EventA lazy reference to an event by id.
An event that loads the first time you read a field. Nothing is sent yet.
getstatic
static get(eventId: string, options?: CallOptions): Promise<Event>Load an event by id now, with its deliveries; an unknown id (or one older than 30 days) throws NotFound.
The event, loaded.
liststatic
static list(options?: EventListOptions & { limit?: number }): Promise<Event[]>Events newest first, from the last 30 days. Outside asUser you read your account's own
events; userFilter reads your users'.
One type or several; * matches the rest of a name (domain.*).
Return at most this many.
Which users the read covers (user_id query), instead of acting as one (user).
undefined = the ambient user (asUser), null = the account itself.
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
Every matching event, fetched page by page (or the first limit).
listPagestatic
static listPage(options?: EventListOptions & PageOptions): Promise<Page<Event>>One page of events; pass nextCursor back as cursor.
The next_cursor of the page before; omit it for the first page.
Return at most this many.
One type or several; * matches the rest of a name (domain.*).
Which users the read covers (user_id query), instead of acting as one (user).
undefined = the ambient user (asUser), null = the account itself.
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
A page whose data holds the events and whose next_cursor is None on the last page.
typesstatic
static types(options?: { client?: NoClick }): Promise<EventType[]>The catalog of event types a webhook can subscribe to, in catalog order (grouped by area).
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
Every event type with what it means, in catalog order (grouped by area).
EventType
interface EventTypeOne kind of event: its name (operation.succeeded), what it means, and its area (the part
before the first dot). emitted is whether NoClick sends it today: the rest are listed so your
code can subscribe before the primitive behind them ships.
| name | string | |
| description | string | |
| emitted | boolean | |
| raw | JsonObject | The response JSON exactly as the API sent it. |
| area | string | What the event is about: |