Store Hugs Developers

Webhook endpoints

The addresses the shop sends its events to: orders, products, customers, quotations and enquiries.

Reach them through admin.webhooks. Reading needs the webhooks:read scope, changing them webhooks:write. An endpoint takes only events your key may read: order events need orders:read, product events and catalog.changed products:read, customer events customers:read, and quotation and enquiry events quotations:read. An app sees and manages only the endpoints it made, which are deleted when the merchant disconnects it. Check each delivery with verifyWebhookSignature.

List webhook endpoints

admin.webhooks.list(query?: ListQuery): Promise<CursorPage<WebhookEndpoint>>

One page of the endpoints your key may see, newest first, or oldest change first with updatedSince. Read the next page with meta.nextCursor as cursor. Scope: webhooks:read.

Parameters

Parameter Type
query object The query fields below, by name.

Query fields

ParameterTypeDescription
limitintegerAt least 1. At most 100. Default 50.
cursorstringmeta.nextCursor (or the cursor in links.next) of the previous page. At most 1000 characters.
updatedSincestring (date-time)Records changed at or after this time (ISO 8601, any offset or Z), oldest change first, for incremental sync.

Returns

A CursorPage<WebhookEndpoint>:

FieldTypeDescription
linksobject
links.firstnull
links.lastnull
links.prevstring (uri) or null
links.nextstring (uri) or null
metaobject
meta.pathstring (uri)
meta.perPageinteger
meta.nextCursorstring or null
meta.prevCursorstring or null
dataarray of WebhookEndpoint
data[].idinteger
data[].urlstring (uri)
data[].eventsarray of string
data[].activeboolean
data[].disabledAtstring (date-time) or nullWhen it was turned off after 20 failed deliveries in a row.
data[].createdAtstring (date-time) or null
data[].updatedAtstring (date-time) or null

Errors

StatusWhen
401invalid_api_key: no active Admin key in Authorization: Bearer.
403admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope.
422Validation errors ({ message, errors }), or an idempotency refusal(idempotency_key_reused, idempotency_key_invalid).
429Rate limited.

Example

const { data: endpoints } = await admin.webhooks.list();

Iterate over every endpoint

admin.webhooks.all(query?: ListQuery): AsyncGenerator<WebhookEndpoint, void, undefined>

Every endpoint matching the query, one at a time, fetching the next page as you read. It takes the same query as list, without cursor. Scope: webhooks:read.

Returns

An async iterable of WebhookEndpoint, each:

FieldTypeDescription
[].idinteger
[].urlstring (uri)
[].eventsarray of string
[].activeboolean
[].disabledAtstring (date-time) or nullWhen it was turned off after 20 failed deliveries in a row.
[].createdAtstring (date-time) or null
[].updatedAtstring (date-time) or null

Example

for await (const endpoint of admin.webhooks.all()) {
    if (!endpoint.active) {
        await admin.webhooks.update(endpoint.id, { active: true });
    }
}

Get a webhook endpoint

admin.webhooks.get(id: number): Promise<WebhookEndpoint>

One endpoint by its id. Scope: webhooks:read.

Parameters

Parameter Type
id number The endpoint's id.

Returns

A WebhookEndpoint:

FieldTypeDescription
idinteger
urlstring (uri)
eventsarray of string
activeboolean
disabledAtstring (date-time) or nullWhen it was turned off after 20 failed deliveries in a row.
createdAtstring (date-time) or null
updatedAtstring (date-time) or null

Errors

StatusWhen
401invalid_api_key: no active Admin key in Authorization: Bearer.
403admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope.
404not_found: the shop has no such record.
429Rate limited.

Add a webhook endpoint

admin.webhooks.create(input: WebhookEndpointInput, options?: RequestOptions): Promise<CreatedWebhookEndpoint>

A new endpoint, which starts on. Its whsec_… signing secret is returned in secret, only this once: keep it to verify deliveries. A shop has at most 10 endpoints (422 limit_reached). Scope: webhooks:write, plus the read scope of each event.

Parameters

Parameter Type
input object The endpoint's fields, below.
options RequestOptions idempotencyKey, signal and headers (see retries).

Request fields

FieldTypeDescription
url requiredstring (uri)An https address on the public internet. At most 500 characters.
events requiredarray of string
activebooleanValidated but ignored when creating; a new endpoint is on.

Returns

A CreatedWebhookEndpoint: the endpoint in data, and its secret:

FieldTypeDescription
dataWebhookEndpoint
data.idinteger
data.urlstring (uri)
data.eventsarray of string
data.activeboolean
data.disabledAtstring (date-time) or nullWhen it was turned off after 20 failed deliveries in a row.
data.createdAtstring (date-time) or null
data.updatedAtstring (date-time) or null
secretstringThe whsec_… signing secret.

Errors

StatusWhen
401invalid_api_key: no active Admin key in Authorization: Bearer.
403admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope.
409idempotency_in_progress: a request with this Idempotency-Key is still running. Retry with the same key after Retry-After seconds; the first answer is then replayed.
422Validation errors, limit_reached, or an idempotency refusal.
429Rate limited.

Example

const { data: endpoint, secret } = await admin.webhooks.create({
    url: 'https://erp.example.com/storehugs/webhooks',
    events: ['order.created', 'order.status_changed', 'product.stock_changed'],
});
// Keep secret to verify deliveries.

Update a webhook endpoint

admin.webhooks.update(id: number, changes: Partial<WebhookEndpointInput>, options?: UpdateOptions): Promise<WebhookEndpoint>

Changes the address, the events or whether the endpoint is on; only what is sent changes. Turning it on resets its failure count. A new address, new events or turning it on needs the read scope of every event it then takes (403 insufficient_scope). Scope: webhooks:write.

Parameters

Parameter Type
id number The endpoint's id.
changes object The fields to change, below.
options UpdateOptions unmodifiedSince (the updatedAt you read; a newer endpoint is refused with 409 edit_conflict) and idempotencyKey.

Request fields

FieldTypeDescription
urlstring (uri)An https address on the public internet. At most 500 characters.
eventsarray of string
activeboolean
updatedAtstring (date-time) or nullThe record's updatedAt as you read it; a newer record gets 409 edit_conflict.

Returns

The changed WebhookEndpoint:

FieldTypeDescription
idinteger
urlstring (uri)
eventsarray of string
activeboolean
disabledAtstring (date-time) or nullWhen it was turned off after 20 failed deliveries in a row.
createdAtstring (date-time) or null
updatedAtstring (date-time) or null

Errors

StatusWhen
401invalid_api_key: no active Admin key in Authorization: Bearer.
403admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope.
404not_found: the shop has no such record.
409edit_conflict (the record changed after If-Unmodified-Since or updatedAt), or idempotency_in_progress.
422Validation errors ({ message, errors }), or an idempotency refusal(idempotency_key_reused, idempotency_key_invalid).
429Rate limited.

Example

const endpoint = await admin.webhooks.get(2);
await admin.webhooks.update(
    2,
    { events: [...endpoint.events, 'order.refunded'] },
    { unmodifiedSince: endpoint.updatedAt ?? undefined },
);

Delete a webhook endpoint

admin.webhooks.delete(id: number): Promise<void>

Deletes an endpoint. Scope: webhooks:write.

Parameters

Parameter Type
id number The endpoint's id.

Returns

Nothing.

Errors

StatusWhen
401invalid_api_key: no active Admin key in Authorization: Bearer.
403admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope.
404not_found: the shop has no such record.
409idempotency_in_progress: a request with this Idempotency-Key is still running. Retry with the same key after Retry-After seconds; the first answer is then replayed.
422Validation errors ({ message, errors }), or an idempotency refusal(idempotency_key_reused, idempotency_key_invalid).
429Rate limited.