Authentication
Valid key returns 200 on /me
401, your token is malformed or revoked.Missing Authorization returns 401
/api/v1/partner/....Scope list matches what you requested
scopes field in the /me response should contain identity:read plus any scopes granted to your key (e.g. webhooks:manage). If a scope you expected is missing, ask your VantageClaw contact to re-issue the key.Webhook subscription
Subscription created with secret captured
POST /api/v1/partner/webhooks response includes a secret field. Confirm it was stored in your secret manager before the response was discarded — there is no recovery path.Subscription appears in list
GET /api/v1/partner/webhooks should return your subscription with active: true, consecutive_failures: 0, and auto_disabled_at: null. The secret is omitted from list responses, which is expected.URL validation rejects internal hosts
http://localhost:8080, http://192.168.1.1/, or https://server.local. All three should return 422 with a validation error. If any succeed, you are not hitting the partner API namespace.Signature verification
Valid test event is accepted
POST /api/v1/partner/webhooks/{id}/test with the correct secret in the body. Your handler should log a verified event and return 2xx.Tampered body is rejected
Old timestamp is rejected
X-VC-Timestamp set to a value more than 5 minutes in the past, signed with that timestamp. Your handler must reject it. If it accepts, your replay-window check is not running.Wrong secret is rejected
return True hidden in error-handling.Delivery semantics
Handler responds within 10 seconds
2xx first, process asynchronously.Handler is idempotent on event id
--include-retries (or by returning 500 once to force a real retry). The second delivery has the same evt_<uuid> in the body. Your handler should detect the duplicate and not double-process.Failed deliveries appear in the failures audit
500 from your handler. Within seconds, GET /api/v1/partner/webhooks/{id}/failures should show the failed attempt with http_status: 500. Confirm pagination works by listing with ?limit=10.Subscription survives a brief outage
Operational readiness
Secret rotation procedure tested
- Create a second subscription with the same URL.
- Update your handler to accept either secret.
- Verify traffic flows to the new subscription.
- Delete the old subscription.
- Update your handler to drop the old secret.
Failed-delivery alerting wired
GET /webhooks and checking active/auto_disabled_at, or by polling GET /webhooks/{id}/failures. Decide your alert cadence and wire it in before going live.Secret stored in secret manager, not source code
grep -r "whsec_" . in your codebase should return zero matches. The secret lives in environment variables, a secret manager, or an encrypted config — never in committed source.Clock sync is healthy
timedatectl status (Linux) or equivalent should show synchronized NTP. The signature timestamp window is ±5 minutes — clock drift beyond that breaks legitimate verification.When all checks pass
You are ready to receive real events as soon as the relevant event categories ship. Your handler will verify and process them with no code changes — every future event type uses the same envelope shape and signature algorithm asvc.test.ping.
If a check fails and you can’t immediately diagnose, capture:
- The full headers of the failing request (with
X-VC-SignatureandX-VC-Timestamp) - The exact body bytes you signed against (length in bytes is the most useful diagnostic)
- The
evt_<uuid>from the response