Send a signed test event
Send one signed test event to an endpoint and report what came back.
Send one signed test event to an endpoint and report what came back.
Give it either a callback_url or the subscription_id of an existing
subscription. With subscription_id the test uses that subscription
exactly as configured — its URL, method, stored headers and stored signing
secret — which is the only way to prove that what is stored actually works.
Not both. A subscription_id together with a DIFFERENT
callback_url is a 400. The stored headers and signing secret are
write-only and are only ever sent to the subscription's own URL; to test
another endpoint, send that callback_url on its own with whatever
headers and secret you want used.
This is a test, not a delivery. One attempt, a 10-second budget, no
retry ladder, and nothing is written to the delivery ledger. The
delivery_id in the
response is synthetic and will not appear in GET /v2/webhooks/deliveries.
The payload is shaped like a real event — the same envelope keys, the
same signature scheme — with synthetic values and an extra test: true
key. The signature is HMAC-SHA256 over "<timestamp>." + body in the
X-Graine-Signature header as t=<unix>,v1=<hex>; verify by
recomputing over the raw body bytes and rejecting a stale t.
signed comes back false when no secret is configured for the
subscription or the organisation. That is the same state the ledger records
as signed: false, and it means your signature check can never pass.
Your endpoint's response body is deliberately not echoed — only its status code, an error class and the elapsed time. The URL is re-checked against its RESOLVED addresses before the request is made, because this endpoint dials on demand from our network.
A 202 means the test was attempted; read delivered for the outcome. A
non-2xx from your endpoint is a successful test with delivered: false,
not an error from this API.
Errors: 400 (neither callback_url nor subscription_id, or a refused URL), 401, 403, 404 (no such subscription in this organisation), 422, 429, 503.
Rate limit: 1000 requests per minute per organization (bucket default). Exceeding it returns 429 with Retry-After; the X-RateLimit-* response headers report your remaining allowance on every call.
v2/webhooks/testAuthorization
AuthorizationRequiredBearer <token>
Your Graine API key. Create one in the dashboard under Developers, or via POST /v2/api-keys. Send it as Authorization: Bearer <key>.
In: header
Request Body
application/jsonRequiredcallback_urlCallback Url | null
Where to send the test. Required unless subscription_id is given.
2048subscription_idSubscription Id | null
Test an existing subscription exactly as it is configured — its URL, method, headers and secret.
event_typeEvent Type | null
Event type to stamp on the test payload. Valid event types: all_processing_completed, call_completed, call_corrected, call_ringing, call_started, client_analysis_completed, platform_analysis_completed, recording_completed. Omitting event_types, or sending an empty list, resolves to all_processing_completed — there is no value that means "every event".
agent_idAgent Id | null
Stamped on the test payload only.
method_typeMethod Type | null
POST or PUT. Defaults to POST.
headersHeaders | null
Extra headers for this test only. Nothing is stored.
secretSecret | null
Sign the test with this secret instead of the stored one. Nothing is stored.
Query Parameters
organization_idOrganization Id
Must match the organisation the API key belongs to.
Response Body
202
What we sent and what your endpoint answered.
acceptedRequiredAccepted
Always true — the test request was built and attempted.
deliveredRequiredDelivered
True when your endpoint answered 2xx.
http_statusHttp Status | null
Status your endpoint returned, or null if the request never completed.
error_classError Class | null
dns_error | timeout | connect_error | tls_error | http_error | null.
error_messageError Message | null
Capped error detail, no response body.
duration_msRequiredDuration Ms
Wall time of the attempt.
signedRequiredSigned
True when an X-Graine-Signature header was sent. False means no secret is configured for this subscription or organisation.
signature_headerRequiredSignature Header
Name of the signature header.
event_typeRequiredEvent Type
Event type stamped on the test payload.
event_idRequiredEvent Id
Unique per test call.
delivery_idRequiredDelivery Id
Synthetic id; it is NOT in the delivery ledger.
callback_hostCallback Host | null
Host we sent the test to.
method_typeRequiredMethod Type
POST or PUT.
sent_header_namesRequiredSent Header Names
Names of every header we sent. Values are never echoed.
bodyRequiredBody
The exact test payload we signed and sent.
400
1000 — malformed input the schema could not reject: an unknown event type, a method other than POST/PUT, a reserved header name, or a callback_url pointing at a private, loopback or metadata address.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
401
1100 — missing, unknown or inactive API key. 1101 — a browser session token was presented instead of a gat_ key.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
403
1102 — the key is valid but lacks the scope this endpoint requires, or names another organisation. GET /v2/scopes reports which scopes the key holds.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
404
1200 — no such subscription or delivery in this organisation. Cross-tenant reads answer 404, never 403.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
422
1001 — the body or query failed validation; the message names the first offending field.
errorRequiredinteger
Stable integer code from the error table. Branch on this, not on the message.
messageRequiredstring
One human-readable sentence. Wording may change; the code will not.
429
1300 — per-organisation rate limit exceeded. Carries Retry-After.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
503
1501 — the webhook subscription store is unreachable.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
504
1502 — an upstream did not respond in time.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
What we sent and what your endpoint answered.

