Set up webhooks with AI
Paste one prompt. Your AI reads our docs and catalog, creates the webhook, writes the handler for your framework, tests it, and shows you the proof that it passed. The prompts hold no keys or secrets. For a prompt pre-filled with your own events, filters and URL, use the dashboard setup.
Before you start
- Create a key in the dashboard and put it in the env var
CITO_API_KEY. Never paste it into the chat. - Live delivery is on Pro and Scale. On any plan, your AI can use a test inbox with real samples and hand you working code.
- A key can create webhooks, so the account owner gets an email when a key creates one or changes its URL.
Prompts
Change the goal and events to suit. Each one fits in a chat, and each tells the AI to prove the result rather than claim it.
Store results (CS2, Next.js)
Set up Cito sports data webhooks in this project so I can store results as matches finish. Stack: Next.js (App Router).
Read first: https://citoapi.com/docs/webhooks.md. Event list: https://api.citoapi.com/api/v1/webhooks/events?examples=false. A real example of one event: https://api.citoapi.com/api/v1/webhooks/events?event=NAME. Every path below is under https://api.citoapi.com/api/v1.
Events: cs2.match.completed
Filters: none
Endpoint: add a POST route to this project. If it is not public yet, test with a Cito test inbox first.
Do this:
1. Secrets: read CITO_API_KEY from an env var. If it is missing, tell me to set it; do not ask me to paste it. Keep it and all webhook secrets out of code, logs, commits and this chat.
2. Create: POST /webhooks with header x-api-key and {"url","events","filters"}, from a script that writes webhook.secret straight to the gitignored env file as CITO_WEBHOOK_SECRET without printing it. It is shown once. The MCP tool create_webhook also works, but it puts the secret in this chat.
3. Handler: compute hex HMAC-SHA256 of the raw request bytes with the secret and compare to X-Cito-Signature in constant time, before parsing JSON. Mismatch: 401.
4. Answer 2xx within 10 seconds, then do the work.
5. Dedupe on the payload id (same as X-Cito-Event-Id, stable across retries and replays). A replay has data.replayed true, so make the work safe to repeat. A test has test: true: never apply it to real data. Do not assume order.
6. After 3 straight failures sending pauses (1, 5, 15, then 30 minutes). When delivery recovers, Cito re-sends up to 50 missed match and result events from the last 24 hours. For older ones, add a way to call POST /webhooks/{id}/catch-up with {"dryRun":true} first, then without.
7. Test: an inbox stores requests and never forwards them. See a real payload with POST /webhook-inbox, then POST /webhook-inbox/{id}/sample with {"event":"..."}. Run my handler locally against that body as in "Test your handler locally" in the docs. If my handler has a public URL, also POST /webhooks/{id}/test with {"event":"..."}.
8. Prove it: show me the local run's verified signature and, if a webhook exists, status, statusCode, latencyMs and diagnosis from the test. Do not say it works until you have that, and say what you could not test.
If an event's status in the catalog is not "active", tell me before relying on it. Live delivery needs Pro or Scale: if create returns WEBHOOK_PLAN_REQUIRED, there is no webhook, so finish with the inbox and the local run, and give me upgradeUrl.Live scoreboard (LoL, Express)
Set up Cito sports data webhooks in this project so I can keep a live scoreboard updated while matches are played. Stack: Node with Express.
Read first: https://citoapi.com/docs/webhooks.md. Event list: https://api.citoapi.com/api/v1/webhooks/events?examples=false. A real example of one event: https://api.citoapi.com/api/v1/webhooks/events?event=NAME. Every path below is under https://api.citoapi.com/api/v1.
Events: lol.live.game_started, lol.live.state, lol.score.updated, lol.match.completed
Filters: none
Endpoint: add a POST route to this project. If it is not public yet, test with a Cito test inbox first.
Do this:
1. Secrets: read CITO_API_KEY from an env var. If it is missing, tell me to set it; do not ask me to paste it. Keep it and all webhook secrets out of code, logs, commits and this chat.
2. Create: POST /webhooks with header x-api-key and {"url","events","filters"}, from a script that writes webhook.secret straight to the gitignored env file as CITO_WEBHOOK_SECRET without printing it. It is shown once. The MCP tool create_webhook also works, but it puts the secret in this chat.
3. Handler: compute hex HMAC-SHA256 of the raw request bytes with the secret and compare to X-Cito-Signature in constant time, before parsing JSON. Mismatch: 401.
4. Answer 2xx within 10 seconds, then do the work.
5. Dedupe on the payload id (same as X-Cito-Event-Id, stable across retries and replays). A replay has data.replayed true, so make the work safe to repeat. A test has test: true: never apply it to real data. Do not assume order.
6. After 3 straight failures sending pauses (1, 5, 15, then 30 minutes). When delivery recovers, Cito re-sends up to 50 missed match and result events from the last 24 hours. For older ones, add a way to call POST /webhooks/{id}/catch-up with {"dryRun":true} first, then without.
7. Test: an inbox stores requests and never forwards them. See a real payload with POST /webhook-inbox, then POST /webhook-inbox/{id}/sample with {"event":"..."}. Run my handler locally against that body as in "Test your handler locally" in the docs. If my handler has a public URL, also POST /webhooks/{id}/test with {"event":"..."}.
8. Prove it: show me the local run's verified signature and, if a webhook exists, status, statusCode, latencyMs and diagnosis from the test. Do not say it works until you have that, and say what you could not test.
If an event's status in the catalog is not "active", tell me before relying on it. Live delivery needs Pro or Scale: if create returns WEBHOOK_PLAN_REQUIRED, there is no webhook, so finish with the inbox and the local run, and give me upgradeUrl.Settle bets (tennis, FastAPI)
Set up Cito sports data webhooks in this project so I can settle bets and predictions when a result is final. Stack: Python with FastAPI.
Read first: https://citoapi.com/docs/webhooks.md. Event list: https://api.citoapi.com/api/v1/webhooks/events?examples=false. A real example of one event: https://api.citoapi.com/api/v1/webhooks/events?event=NAME. Every path below is under https://api.citoapi.com/api/v1.
Events: tennis.match.completed, tennis.match.stats_ready
Filters: none
Endpoint: add a POST route to this project. If it is not public yet, test with a Cito test inbox first.
Do this:
1. Secrets: read CITO_API_KEY from an env var. If it is missing, tell me to set it; do not ask me to paste it. Keep it and all webhook secrets out of code, logs, commits and this chat.
2. Create: POST /webhooks with header x-api-key and {"url","events","filters"}, from a script that writes webhook.secret straight to the gitignored env file as CITO_WEBHOOK_SECRET without printing it. It is shown once. The MCP tool create_webhook also works, but it puts the secret in this chat.
3. Handler: compute hex HMAC-SHA256 of the raw request bytes with the secret and compare to X-Cito-Signature in constant time, before parsing JSON. Mismatch: 401.
4. Answer 2xx within 10 seconds, then do the work.
5. Dedupe on the payload id (same as X-Cito-Event-Id, stable across retries and replays). A replay has data.replayed true, so make the work safe to repeat. A test has test: true: never apply it to real data. Do not assume order.
6. After 3 straight failures sending pauses (1, 5, 15, then 30 minutes). When delivery recovers, Cito re-sends up to 50 missed match and result events from the last 24 hours. For older ones, add a way to call POST /webhooks/{id}/catch-up with {"dryRun":true} first, then without.
7. Test: an inbox stores requests and never forwards them. See a real payload with POST /webhook-inbox, then POST /webhook-inbox/{id}/sample with {"event":"..."}. Run my handler locally against that body as in "Test your handler locally" in the docs. If my handler has a public URL, also POST /webhooks/{id}/test with {"event":"..."}.
8. Prove it: show me the local run's verified signature and, if a webhook exists, status, statusCode, latencyMs and diagnosis from the test. Do not say it works until you have that, and say what you could not test.
If an event's status in the catalog is not "active", tell me before relying on it. Live delivery needs Pro or Scale: if create returns WEBHOOK_PLAN_REQUIRED, there is no webhook, so finish with the inbox and the local run, and give me upgradeUrl.Alerts (UFC, Flask)
Set up Cito sports data webhooks in this project so I can send Discord alerts when fights start and finish. Stack: Python with Flask.
Read first: https://citoapi.com/docs/webhooks.md. Event list: https://api.citoapi.com/api/v1/webhooks/events?examples=false. A real example of one event: https://api.citoapi.com/api/v1/webhooks/events?event=NAME. Every path below is under https://api.citoapi.com/api/v1.
Events: ufc.fight.started, ufc.fight.completed
Filters: none
Endpoint: add a POST route to this project. If it is not public yet, test with a Cito test inbox first.
Do this:
1. Secrets: read CITO_API_KEY from an env var. If it is missing, tell me to set it; do not ask me to paste it. Keep it and all webhook secrets out of code, logs, commits and this chat.
2. Create: POST /webhooks with header x-api-key and {"url","events","filters"}, from a script that writes webhook.secret straight to the gitignored env file as CITO_WEBHOOK_SECRET without printing it. It is shown once. The MCP tool create_webhook also works, but it puts the secret in this chat.
3. Handler: compute hex HMAC-SHA256 of the raw request bytes with the secret and compare to X-Cito-Signature in constant time, before parsing JSON. Mismatch: 401.
4. Answer 2xx within 10 seconds, then do the work.
5. Dedupe on the payload id (same as X-Cito-Event-Id, stable across retries and replays). A replay has data.replayed true, so make the work safe to repeat. A test has test: true: never apply it to real data. Do not assume order.
6. After 3 straight failures sending pauses (1, 5, 15, then 30 minutes). When delivery recovers, Cito re-sends up to 50 missed match and result events from the last 24 hours. For older ones, add a way to call POST /webhooks/{id}/catch-up with {"dryRun":true} first, then without.
7. Test: an inbox stores requests and never forwards them. See a real payload with POST /webhook-inbox, then POST /webhook-inbox/{id}/sample with {"event":"..."}. Run my handler locally against that body as in "Test your handler locally" in the docs. If my handler has a public URL, also POST /webhooks/{id}/test with {"event":"..."}.
8. Prove it: show me the local run's verified signature and, if a webhook exists, status, statusCode, latencyMs and diagnosis from the test. Do not say it works until you have that, and say what you could not test.
If an event's status in the catalog is not "active", tell me before relying on it. Live delivery needs Pro or Scale: if create returns WEBHOOK_PLAN_REQUIRED, there is no webhook, so finish with the inbox and the local run, and give me upgradeUrl.No server yet (any sport, Go)
Set up Cito sports data webhooks in this project so I can see real events and have a handler ready for when I deploy. Stack: Go (net/http).
Read first: https://citoapi.com/docs/webhooks.md. Event list: https://api.citoapi.com/api/v1/webhooks/events?examples=false. A real example of one event: https://api.citoapi.com/api/v1/webhooks/events?event=NAME. Every path below is under https://api.citoapi.com/api/v1.
Events: cs2.match.completed
Filters: none
Endpoint: no public server yet. Use a Cito test inbox: POST /webhook-inbox (GET /webhook-inbox lists mine).
Do this:
1. Secrets: read CITO_API_KEY from an env var. If it is missing, tell me to set it; do not ask me to paste it. Keep it and all webhook secrets out of code, logs, commits and this chat.
2. Create: POST /webhooks with header x-api-key and {"url","events","filters"}, from a script that writes webhook.secret straight to the gitignored env file as CITO_WEBHOOK_SECRET without printing it. It is shown once. The MCP tool create_webhook also works, but it puts the secret in this chat.
3. Handler: compute hex HMAC-SHA256 of the raw request bytes with the secret and compare to X-Cito-Signature in constant time, before parsing JSON. Mismatch: 401.
4. Answer 2xx within 10 seconds, then do the work.
5. Dedupe on the payload id (same as X-Cito-Event-Id, stable across retries and replays). A replay has data.replayed true, so make the work safe to repeat. A test has test: true: never apply it to real data. Do not assume order.
6. After 3 straight failures sending pauses (1, 5, 15, then 30 minutes). When delivery recovers, Cito re-sends up to 50 missed match and result events from the last 24 hours. For older ones, add a way to call POST /webhooks/{id}/catch-up with {"dryRun":true} first, then without.
7. Test: an inbox stores requests and never forwards them. See a real payload with POST /webhook-inbox, then POST /webhook-inbox/{id}/sample with {"event":"..."}. Run my handler locally against that body as in "Test your handler locally" in the docs. If my handler has a public URL, also POST /webhooks/{id}/test with {"event":"..."}.
8. Prove it: show me the local run's verified signature and, if a webhook exists, status, statusCode, latencyMs and diagnosis from the test. Do not say it works until you have that, and say what you could not test.
If an event's status in the catalog is not "active", tell me before relying on it. Live delivery needs Pro or Scale: if create returns WEBHOOK_PLAN_REQUIRED, there is no webhook, so finish with the inbox and the local run, and give me upgradeUrl.Claude
Settings, Connectors, Add custom connector, with the server URL https://api.citoapi.com/mcp. Your browser opens a Cito page; choose Allow, so no key is typed. Then paste a prompt. On a chat with no project, ask for the handler code as a file and for the commands to run.
Claude Code
Set CITO_API_KEY in your shell, connect once, then run claude in your project and paste a prompt.
claude mcp add --transport http cito https://api.citoapi.com/mcp --header "x-api-key: $CITO_API_KEY"Or install for every MCP client on this machine:
npx cito-mcp install --key cito_your_key_hereCodex
Add the server to your config, or run the install command above. Then run codex in your project and paste a prompt.
# ~/.codex/config.toml
[mcp_servers.cito]
command = "npx"
args = ["-y", "cito-mcp"]
env = { CITO_API_KEY = "cito_your_key_here" }ChatGPT
Settings, Connectors (developer mode), add https://api.citoapi.com/mcp, sign in and allow. ChatGPT cannot edit your project, so ask for the handler file and the commands to run. Without the connector, it can still write the code from the prompt and the docs.
Cursor
Add this to .cursor/mcp.json, keep that file out of git, and paste a prompt into Agent mode.
{
"mcpServers": {
"cito": { "url": "https://api.citoapi.com/mcp", "headers": { "x-api-key": "cito_your_key_here" } }
}
}MCP tools
All of these touch only your own webhooks and test inboxes.
explain_webhook_setuplist_webhook_eventslist_webhookscreate_webhookupdate_webhookdelete_webhook (needs confirm: true)regenerate_webhook_secrettest_webhookwebhook_deliveriesreplay_webhookcatch_up_webhookcreate_webhook_inboxlist_webhook_inboxesread_webhook_inboxsend_inbox_sampleclear_webhook_inboxdelete_webhook_inbox
If you are an AI reading this
- Read /docs/webhooks.md and the per-sport files it links, then
GET https://api.citoapi.com/api/v1/webhooks/eventsfor current status. - Take the key from
CITO_API_KEY. Write the secret straight to a gitignored env file without printing it. - Failures carry
codeandfix: followfix. OnWEBHOOK_PLAN_REQUIRED, finish with a test inbox and give the userupgradeUrl. - Do not say it works until
POST /webhooks/{id}/testreturnedstatus: deliveredand the handler logged a verified signature.