provisioned_participant and any rejection.
Only terminal outcomes are delivered. Intermediate states (DocV in progress, manual review) produce no webhook — poll
GET /v1/kyc/status if you need to track them.Register your webhook
POST /v1/kyc/webhook — requires the write:kyc scope. Register once per firm (not per participant). Registration runs a test POST to your URL before saving; if the test fails, nothing is saved and you may retry.
Also available over gRPC as
polymarket.us.kyc.v1.KYCAPI/SetWebhookURL with the same two fields and the same validation behavior — see the transport mapping.Request fields
Response
Test-POST contract
Registration sends aPOST to your URL with a normal notification envelope whose event_type is webhook.test and whose data is a fixed informational message. It is signed (same scheme as real deliveries) when you supplied a signing_secret. Your endpoint passes only by returning a 2xx. Redirects are not followed, and URLs that resolve to private or internal IP ranges are refused.
Receiving notifications
Polymarket US sends an HTTPPOST with a JSON body to your registered URL.
Headers
Signed deliveries follow the Standard Webhooks convention. The three signing headers are present only when a signing secret is configured.Body
Webhook
data fields are snake_case (e.g. external_id, provisioned_participant), unlike the camelCase REST responses. See Field naming.Event types
data fields
Empty fields are omitted from the JSON.
Using these identifiers to trade
When you place an order on behalf of a participant,provisioned_participant is the “who” — pass it as the x-participant-id header on participant-scoped requests (trading, positions, reports). It is the only provisioning identifier you need.
The webhook and
GET /v1/kyc/status carry the same value under different field names — the webhook calls it provisioned_participant, while the status read calls it participantId.
Delivery semantics
- At-least-once. Deduplicate on
event_id(thewebhook-idheader) — you may receive the same event more than once. - Retries. Only a
2xxcounts as delivered. Redirects are not followed (a3xxis a failed delivery); every non-2xx or transport error is retried with jittered exponential backoff up to a maximum attempt count.Retry-Afteris honored on408/429. A repeatedly-failing endpoint is circuit-broken: deliveries pause for a cooldown that grows with each consecutive re-open, then resume. - Respond fast. Return
2xxpromptly once you’ve durably accepted the event; do heavy processing asynchronously.
Verifying the signature
Because the secret is in the standardwhsec_/base64 format, a Standard Webhooks SDK verifies deliveries out of the box — initialise it with the default constructor (e.g. NewWebhook in Go), passing the secret exactly as you registered it. No raw-key escape hatch (NewWebhookRaw) is needed.
If you verify inline instead, the signed content is <webhook-id>.<webhook-timestamp>.<raw body> — the raw request bytes, before any JSON re-serialization. The HMAC key is the decoded Standard Webhooks key: strip the optional whsec_ prefix from your signing_secret and base64-decode the remainder using standard padded base64. Compute the expected signature, then constant-time compare it against each space-delimited candidate in webhook-signature; accept if any matches.
Next steps
Verification Flow
The synchronous outcomes that precede these webhooks.
Overview
How the KYC process fits together.