grant.revoked, when a grant ends, and ping, when you ask for a test.
MyPilotIndex sets your webhook URL (https only) and its signing secret when it approves you. The secret starts with whsec_ and is shown once.
Delivery
Each event is aPOST of the event as JSON (Content-Type: application/json). Answer any 2xx within 10 seconds.
Headers, in the Standard Webhooks scheme:
Verifying the signature
The key is the base64 content of your secret after thewhsec_ prefix. Compute the HMAC over the exact bytes you received, not over a re-serialized body, compare in constant time, and refuse a timestamp more than five minutes from your clock.
grant.revoked
reason is pilot (he disconnected you in Settings), operator (MyPilotIndex revoked it) or account_deleted (he deleted his account, so the grant no longer appears in any list).
When you receive it, delete what you hold from MyPilotIndex for that pilot, as the data agreement requires. From that moment every call naming the grant answers 404.
Retries
A5xx, a 408, a 429, a redirect (never followed), a timeout or a connection failure is retried with growing gaps for about a day, twelve attempts in all, with the same webhook-id and a fresh timestamp and signature. A 4xx other than 408 and 429 is taken as a refusal and not retried.
The exception is grant.revoked with reason account_deleted: its grant leaves every list with the account, so it cannot be reconciled later. It is retried within the same window on any answer but a 2xx, a 4xx included. Acknowledge it with a 2xx once you have taken it, even if you hold nothing for that pilot.
If you missed other events, reconcile with GET /v1/partner/grants?status=revoked&changed_since=<time>.
Testing
POST /v1/partner/webhooks/test queues one signed ping to your webhook URL and answers 202 before delivery. The ping event has an empty data object. If no webhook URL (https) or secret is on record the answer is 409 with reason webhook_not_configured.
