One subscription: url, events, active, mode, and rotation state. Never the signing secret.
- Credential
- An API key in
x-api-key - Scopes
webhooks:manage
Parameters
idpath · stringrequired
Request
GET /api/v1/webhooks/{id}
curl "https://portal.printedsimply.com/api/v1/webhooks/whk_SV8d5wGm2kUnSwx_RhZfY9OE" \
-H "x-api-key: ps_test_YOUR_KEY"Response 200
The subscription. Never the secret — only create and rotate return that.
data
idstringrequiredurlstringrequiredeventsstring[]requiredactivebooleanrequiredmodestringrequiredWhich order mode this subscription accepts. Normalised on the way out, so a stored value this build does not know reads as what it is actually routed as (
all) rather than as the stored string.One of
alltestlivecreated_atstring (date-time)requiredsecret_rotated_atstring (date-time) | nullprevious_secret_expires_atstring (date-time) | nullDuring a rotation both secrets verify until this moment. Sign-check against both, or accept the older one, until it passes.
rotation_pendingbooleanTrue while the previous secret is still inside its window.
inboxbooleanrequiredTrue for the account's hosted test inbox (POST /v1/webhooks/inbox): it receives test events only and keeps them for GET /v1/webhooks/inbox rather than POSTing them, its
urlis the dashboard page that shows them, and its url and mode cannot be changed.
meta
pageintegertotalintegerlimitintegerThe page size actually applied, which is not necessarily the one asked for — the operation's own ceiling wins.
pagesintegertotaloverlimit, rounded up.next_cursorstring | nullOn a cursor-paged operation: send this back as
cursorfor the next page. Null on the last page. Absent on operations that do not page by cursor.has_morebooleanOn a list operation whose
metaisListMeta: whether another page follows this one.
{
"status": "success",
"data": {
"id": "whk_hCyrY24j_gUrQWxJ7ji6s9st",
"url": "https://example.com/hooks/orders",
"events": [
"order.shipped",
"order.delivered"
],
"active": true,
"mode": "test",
"created_at": "2026-10-15T15:00:26.000Z",
"secret_rotated_at": null,
"previous_secret_expires_at": null,
"rotation_pending": false,
"inbox": false
},
"request_id": "4e3753e1-48dd-4313-bfd8-48e4af4e116a"
}Errors
Missing, invalid or expired API key:
missing_api_key(none sent),invalid_api_key(unknown or revoked),key_expired(past the expiry set when it was created; create a new key).404Resource not found
Rate limit exceeded. Two windows can produce this status and
error.codesays which:rate_limit_exceededfor the per-minute sliding window,daily_quota_exceededfor the plan's daily quota. Both carryRetry-After; the daily one also carriesX-Daily-LimitandX-Daily-Remaining. The per-minute limits are plan-based — see Rate Limits above, or call GET /v1/me for this credential's own figures.