{"success":true,"events":[{"event":"cod.transfer.new","game":"cod","kind":"summary","description":"New Call of Duty roster moves were recorded. A count only: data.count and data.timestamp, with no player names.","whenFires":"When a refresh finds new roster moves.","status":"active","statusNote":"Sent during the last 7 days.","typicalFrequency":"about 4 per day across all matches","last7Days":28,"lastSentAt":"2026-11-08T17:19:34.299Z","latency":{"p50Ms":1008,"p95Ms":4855,"deliveries":119,"basis":"From the moment Cito recorded the event to the moment a customer endpoint answered, recent deliveries."},"minimumPlan":"pro","plans":["PRO","BUSINESS","ENTERPRISE","ONE_GAME_STARTER (own game)","BASIC"],"filters":[],"filtersNote":"This event carries none of the filter fields, so do not add a filter to a webhook that needs it.","payloadBytes":{"average":189,"max":190,"sampledRows":300},"notes":"Treat it as a signal to re-read /cod/transfers. It carries no entity ids.","fields":[{"name":"count","types":["number"],"presentPct":100},{"name":"timestamp","types":["string"],"presentPct":100}],"example":{"event":"cod.transfer.new","id":"a1b2c3d4-0000-4000-8000-000000000000","timestamp":"2026-11-05T17:25:25.657Z","event_type":"cod.transfer.new","match_id":null,"previous_state":null,"data":{"count":10,"timestamp":"2026-11-05T17:25:25.618Z"}},"exampleCapturedAt":"2026-11-05T17:25:25.657Z","docsUrl":"https://citoapi.com/docs/webhooks/#cod-transfer-new"},{"event":"cod.match.live_update","game":"cod","kind":"live_tick","description":"Live map progression and score changes for a Call of Duty match.","whenFires":"During a live match.","status":"not_observed","statusNote":"You can subscribe, but none has been recorded. Do not rely on it.","typicalFrequency":"none recorded so far","last7Days":0,"lastSentAt":null,"latency":null,"minimumPlan":"pro","plans":["PRO","BUSINESS","ENTERPRISE","ONE_GAME_STARTER (own game)","BASIC"],"filters":[],"filtersNote":"Not known yet: no stored event to read them from.","payloadBytes":null,"fields":[],"example":null,"exampleCapturedAt":null,"docsUrl":"https://citoapi.com/docs/webhooks/#cod-match-live_update"},{"event":"cod.match.completed","game":"cod","kind":"summary","description":"Call of Duty matches finished. A count only: data.matchesCompleted and data.timestamp, with no match ids.","whenFires":"When a refresh finds newly completed matches.","status":"quiet","statusNote":"You can subscribe, but it has not been sent recently. Do not build on it alone without checking lastSentAt.","typicalFrequency":"none in the last 7 days; last sent 2026-10-14","last7Days":0,"lastSentAt":"2026-10-14T16:45:07.511Z","latency":{"p50Ms":1679,"p95Ms":5982,"deliveries":445,"basis":"From the moment Cito recorded the event to the moment a customer endpoint answered, recent deliveries."},"minimumPlan":"pro","plans":["PRO","BUSINESS","ENTERPRISE","ONE_GAME_STARTER (own game)","BASIC"],"filters":[],"filtersNote":"This event carries none of the filter fields, so do not add a filter to a webhook that needs it.","payloadBytes":{"average":207,"max":207,"sampledRows":300},"notes":"Treat it as a signal to re-read /cod/matches. It carries no entity ids.","fields":[{"name":"matchesCompleted","types":["number"],"presentPct":100},{"name":"timestamp","types":["string"],"presentPct":100}],"example":{"event":"cod.match.completed","id":"a1b2c3d4-0000-4000-8000-000000000000","timestamp":"2026-10-14T16:45:07.511Z","event_type":"cod.match.completed","match_id":null,"previous_state":null,"data":{"timestamp":"2026-10-14T16:45:07.463Z","matchesCompleted":14}},"exampleCapturedAt":"2026-10-14T16:45:07.511Z","docsUrl":"https://citoapi.com/docs/webhooks/#cod-match-completed"},{"event":"cod.standings.updated","game":"cod","kind":"summary","description":"Call of Duty standings were refreshed. A count only: data.count and data.timestamp.","whenFires":"On each standings refresh, whether or not a position moved.","status":"active","statusNote":"Sent during the last 7 days.","typicalFrequency":"about 96 per day across all matches","last7Days":672,"lastSentAt":"2026-11-08T20:15:04.123Z","latency":{"p50Ms":1211,"p95Ms":5851,"deliveries":2401,"basis":"From the moment Cito recorded the event to the moment a customer endpoint answered, recent deliveries."},"minimumPlan":"pro","plans":["PRO","BUSINESS","ENTERPRISE","ONE_GAME_STARTER (own game)","BASIC"],"filters":[],"filtersNote":"This event carries none of the filter fields, so do not add a filter to a webhook that needs it.","payloadBytes":{"average":200,"max":200,"sampledRows":300},"notes":"Treat it as a signal to re-read standings. It carries no standings rows and does not mean a position changed.","fields":[{"name":"count","types":["number"],"presentPct":100},{"name":"timestamp","types":["string"],"presentPct":100}],"example":{"event":"cod.standings.updated","id":"a1b2c3d4-0000-4000-8000-000000000000","timestamp":"2026-11-08T20:15:04.123Z","event_type":"cod.standings.updated","match_id":null,"previous_state":null,"data":{"count":12,"timestamp":"2026-11-08T20:15:04.083Z"}},"exampleCapturedAt":"2026-11-08T20:15:04.123Z","docsUrl":"https://citoapi.com/docs/webhooks/#cod-standings-updated"},{"event":"cod.player.stats_updated","game":"cod","kind":"summary","description":"Call of Duty player stats changed.","whenFires":"When player stats are updated.","status":"not_observed","statusNote":"You can subscribe, but none has been recorded. Do not rely on it.","typicalFrequency":"none recorded so far","last7Days":0,"lastSentAt":null,"latency":null,"minimumPlan":"pro","plans":["PRO","BUSINESS","ENTERPRISE","ONE_GAME_STARTER (own game)","BASIC"],"filters":[],"filtersNote":"Not known yet: no stored event to read them from.","payloadBytes":null,"fields":[],"example":null,"exampleCapturedAt":null,"docsUrl":"https://citoapi.com/docs/webhooks/#cod-player-stats_updated"},{"event":"cod.tournament.started","game":"cod","kind":"lifecycle","description":"A Call of Duty tournament has started.","whenFires":"When a tournament begins.","status":"not_observed","statusNote":"You can subscribe, but none has been recorded. Do not rely on it.","typicalFrequency":"none recorded so far","last7Days":0,"lastSentAt":null,"latency":null,"minimumPlan":"pro","plans":["PRO","BUSINESS","ENTERPRISE","ONE_GAME_STARTER (own game)","BASIC"],"filters":[],"filtersNote":"Not known yet: no stored event to read them from.","payloadBytes":null,"fields":[],"example":null,"exampleCapturedAt":null,"docsUrl":"https://citoapi.com/docs/webhooks/#cod-tournament-started"},{"event":"cod.tournament.completed","game":"cod","kind":"lifecycle","description":"A Call of Duty tournament has finished.","whenFires":"When a tournament ends.","status":"not_observed","statusNote":"You can subscribe, but none has been recorded. Do not rely on it.","typicalFrequency":"none recorded so far","last7Days":0,"lastSentAt":null,"latency":null,"minimumPlan":"pro","plans":["PRO","BUSINESS","ENTERPRISE","ONE_GAME_STARTER (own game)","BASIC"],"filters":[],"filtersNote":"Not known yet: no stored event to read them from.","payloadBytes":null,"fields":[],"example":null,"exampleCapturedAt":null,"docsUrl":"https://citoapi.com/docs/webhooks/#cod-tournament-completed"}],"count":7,"games":["lol","cod","fortnite","cs2","dota2","tennis","ufc"],"plans":{"live_delivery":{"plans":["PRO","BUSINESS","ENTERPRISE"],"names":"Pro and Scale (and Enterprise)","pro_monthly_usd":59,"scale_monthly_usd":100},"closed_plans":"Accounts still on the closed One Game Starter and Basic plans keep webhooks for the events their plan allows. They cannot subscribe to the real-time CS2 events.","free_and_starter":"Free and Starter accounts can create a test inbox (POST /api/v1/webhook-inbox) and send sample events to it. Live delivery needs Pro or Scale.","upgrade_url":"https://citoapi.com/signup/pro?checkout=1&source=webhook_access","limits":{"webhooks_per_account":5}},"setup":[{"step":1,"title":"Pick events","detail":"GET /api/v1/webhooks/events lists every event, with status, volume, fields and a real example. Subscribe to the fewest that do the job: cs2.player.state_changed alone is hundreds of thousands of requests a week."},{"step":2,"title":"Get a URL","detail":"A public HTTPS route that accepts POST and answers 2xx within 10 seconds. No server yet? POST /api/v1/webhook-inbox gives you a hosted temporary URL, on any plan."},{"step":3,"title":"Create the webhook","detail":"POST /api/v1/webhooks with x-api-key and {\"url\":\"...\",\"events\":[\"...\"],\"filters\":{...}}. Needs Pro or Scale. Save webhook.secret from the response: it is shown once."},{"step":4,"title":"Verify signatures","detail":"HMAC-SHA256 of the raw request body with your secret, hex, compared with the X-Cito-Signature header. Hash the raw bytes before parsing JSON."},{"step":5,"title":"Send a test","detail":"POST /api/v1/webhooks/{id}/test with {\"event\":\"cs2.match.completed\"} sends a real recent sample, signed, marked as a test (X-Cito-Test: true, data.test true, test true). The response has the status code, latency and a plain-English diagnosis."},{"step":6,"title":"Watch deliveries","detail":"GET /api/v1/webhooks/{id}/deliveries lists each delivery. Handle retries with the payload id as your idempotency key."}],"envelope":{"fields":{"event":"The event name.","id":"Unique id of this event. Use it as your idempotency key (same as the X-Cito-Event-Id header).","timestamp":"When Cito sent this delivery, ISO 8601 UTC.","event_type":"The event name.","match_id":"The match id, or null when the event is not about one match.","previous_state":"The state before the change, on events that have one. Otherwise null.","data":"The event body. See fields and example on each event."},"test_markers":"A test delivery has test: true on the envelope, data.test true and the header X-Cito-Test: true. A replay has data.replayed true and data.original_event_id."},"signature_headers":["X-Cito-Signature","X-Cito-Event","X-Cito-Event-Id","X-Cito-Timestamp","X-Cito-Delivery-Attempt","X-Cito-Test (test deliveries only)"],"signing":{"algorithm":"HMAC-SHA256","signedContent":"UTF-8 bytes of the exact JSON request body sent by Cito","bodySerialization":"JSON.stringify(payload)","signatureHeader":"X-Cito-Signature","signatureEncoding":"hex","signaturePrefix":"none","secretFormat":"Use the exact webhook secret value shown when the webhook is created or regenerated. No whsec_ prefix is used.","verificationRule":"Verify against the raw request body bytes before reparsing or reserializing JSON.","sampleSecret":"cito_test_secret_123","samplePayload":{"event":"lol.live.state","id":"sample-event-id-123","timestamp":"2026-06-07T16:00:00.000Z","data":{"gameId":"lol-game-123","matchId":"lol-match-123","league":"LEC","gameTime":1337,"blueTeam":{"tag":"G2","kills":7,"gold":24800,"towers":3,"dragons":2,"barons":0},"redTeam":{"tag":"FNC","kills":5,"gold":23700,"towers":2,"dragons":1,"barons":0}}},"samplePayloadString":"{\"event\":\"lol.live.state\",\"id\":\"sample-event-id-123\",\"timestamp\":\"2026-06-07T16:00:00.000Z\",\"data\":{\"gameId\":\"lol-game-123\",\"matchId\":\"lol-match-123\",\"league\":\"LEC\",\"gameTime\":1337,\"blueTeam\":{\"tag\":\"G2\",\"kills\":7,\"gold\":24800,\"towers\":3,\"dragons\":2,\"barons\":0},\"redTeam\":{\"tag\":\"FNC\",\"kills\":5,\"gold\":23700,\"towers\":2,\"dragons\":1,\"barons\":0}}}","sampleSignature":"97db77f5cd96e09a70dcf6cc75fc5d92d780c41ce82c853b51e4070954c54171","sampleHeaders":{"Content-Type":"application/json","X-Cito-Signature":"97db77f5cd96e09a70dcf6cc75fc5d92d780c41ce82c853b51e4070954c54171","X-Cito-Event":"lol.live.state","X-Cito-Event-Id":"sample-event-id-123","X-Cito-Timestamp":"2026-06-07T16:00:00.000Z","X-Cito-Delivery-Attempt":"1"}},"delivery":{"timeout_ms":10000,"attempts_per_event":3,"retry_gaps_seconds":[1,2],"retried":"Timeouts, network errors, 5xx, 408 and 429.","not_retried":"Other 4xx answers.","success":"Any 2xx answer.","redirects":"307 and 308 keep the POST. 301, 302 and 303 turn it into a GET with no body, so set the webhook to the final URL.","ordering":"Not guaranteed. Use data timestamps or seq-like fields, and treat each event independently.","idempotency":"Use the payload id / X-Cito-Event-Id header as your idempotency key.","failure_pause":{"after_consecutive_failures":3,"pause_minutes":[1,5,15,30],"behaviour":"After 3 failed events in a row, Cito pauses sending to that webhook: 1, then 5, 15 and 30 minutes (30 is the cap). Events that occur during a pause are NOT queued for you. They are logged with status \"skipped_backoff\" and are not sent again unless you ask. Any success ends the pause.","after_recovery":"When the first delivery after a pause succeeds, Cito re-sends up to 50 missed match and result events from the last 24 hours, oldest first, with data.catch_up true and the same event id. POST /api/v1/webhooks/{id}/catch-up re-sends any still missing. POST /api/v1/webhooks/{id}/replay re-sends a specific event or match."},"auto_disable":{"behaviour":"A webhook is switched off (isActive false, reason in lastError) after 100 failures in a row, 20 in a row when the answer is permanent (401, 403, 404, 410, 530, DNS or certificate errors), or 50 in a row with no success for 7 days.","re_enable":"POST /api/v1/webhooks/{id}/reset, or PATCH with {\"isActive\":true}."},"log_note":"attempt in the delivery log is currently always 1, even when retries happened. X-Cito-Delivery-Attempt on the request is the real attempt number.","outbound_addresses":"Deliveries come from Cito servers and may change. Verify X-Cito-Signature instead of allow-listing addresses."},"filters":{"note":"Set on a webhook as {\"filters\":{\"league\":\"LEC\"}}. Each field takes one value or a list, compared case-insensitively. Fields per event are on each event.","fields":{"league":"data.league (for example LEC, Worlds, or cs2 for CS2 events).","matchId":"data.matchId.","gameId":"data.gameId.","side":"data.side.","tour":"Tennis: ATP, WTA and so on.","tournamentId":"Tennis tournament id.","playerId":"Tennis: matches either player."},"tennis_matchId":"For tennis events, matchId matches data.id."},"endpoints":{"catalog":"GET /api/v1/webhooks/events?game=&event=&examples=false&fields=false (public)","openapi":"GET /api/v1/webhooks/openapi.json (public)","list":"GET /api/v1/webhooks","get":"GET /api/v1/webhooks/{id}","create":"POST /api/v1/webhooks","update":"PATCH /api/v1/webhooks/{id}","delete":"DELETE /api/v1/webhooks/{id}","test":"POST /api/v1/webhooks/{id}/test","regenerate_secret":"POST /api/v1/webhooks/{id}/regenerate-secret","reset":"POST /api/v1/webhooks/{id}/reset","deliveries":"GET /api/v1/webhooks/{id}/deliveries","delivery":"GET /api/v1/webhooks/{id}/deliveries/{deliveryId}","replay":"POST /api/v1/webhooks/{id}/replay","catch_up":"POST /api/v1/webhooks/{id}/catch-up","inbox":"POST, GET /api/v1/webhook-inbox"},"auth":"Management routes take your API key (x-api-key header or Authorization: Bearer) or a dashboard session. A key only reaches its own account's webhooks.","measured_at":"2026-11-08T20:30:57.835Z","docs":"https://citoapi.com/docs/webhooks/","dashboard":"https://citoapi.com/dashboard/webhooks"}