Before pointing real platform traffic at your handler, work through this checklist. It mirrors the failure modes we see most often in early integrations.Documentation Index
Fetch the complete documentation index at: https://vantagesolutions.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Authentication
Valid key returns 200 on /me
401, your token is malformed or revoked.Missing Authorization returns 401
The same request without the header should be rejected. If it succeeds, you are not actually using the partner API namespace — check the URL is
/api/v1/partner/....Webhook subscription
Subscription created with secret captured
The
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.Signature verification
Valid test event is accepted
Trigger
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
Manually craft a request to your handler with valid signature headers but a modified body byte. Your handler must return non-2xx. If it accepts the request, your verification is reading the wrong body bytes (likely a JSON re-serialization in your middleware).
Old timestamp is rejected
Manually craft a request with
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.Delivery semantics
Handler responds within 10 seconds
Time your handler under realistic load. The dispatcher times out at 10 seconds per attempt. If your handler does heavy work synchronously, refactor to acknowledge with
2xx first, process asynchronously.Handler is idempotent on event id
Fire the same test event twice with
--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
Deliberately return
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
Take your handler offline for a few minutes, fire a test event, bring the handler back online. The retry schedule (1m, 5m, 30m, 2h, 6h, 24h) should redeliver the event once your handler is healthy. Without bringing it back, after 20 consecutive failures the subscription auto-disables.
Operational readiness
Secret rotation procedure tested
Practice the delete-and-recreate flow in a non-production subscription:
- 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
The auto-disable threshold is 20 consecutive failures. If your subscription gets auto-disabled, the only way to learn is by polling
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.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