{"openapi":"3.1.0","info":{"title":"Champions API","version":"1.0.0","x-logo":{"url":"https://getchampions.io/favicon.svg"},"contact":{"name":"Champions support","email":"support@getchampions.io","url":"https://getchampions.io"},"description":"Champions tracks the people in your CRM - customers, champions, evaluators - and tells you when they change jobs, whether the new company and role fit your ICP, and what play to run.\n\n**Base URL** - `https://api.getchampions.io/v1`. The same API is also served at `https://app.getchampions.io/api/v1`.\n\n**Authentication** - every request needs a workspace API key (Settings → API & integrations) or an OAuth token from the MCP connector. Send it as `Authorization: Bearer chp_live_…` (or `X-API-Key`). Keys carry scopes: `read` for every GET, `write` for POST/PATCH/PUT/DELETE.\n\n**Rate limits** - per workspace: 600 read and 120 write requests per minute. Over the limit you get `429` with `code: rate_limited`.\n\n**Errors** - non-2xx responses are `{ \"error\": { \"code\", \"message\", \"details\"? } }`. Validation failures are `400 validation_error` with a `details` array of `{ path, message }`.\n\n**Credits** - one credit is charged for every profile check (a refresh run checks every tracked profile). Balance and price are on `/credits`; top up at https://app.getchampions.io/billing.\n\n**Webhooks** - register HTTPS endpoints on `/webhooks`. Every delivery is signed: `X-Champions-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" using your endpoint secret>`. Reject deliveries older than 5 minutes and compare in constant time.\n\n**MCP** - the same operations are available to AI agents as a hosted MCP server at `https://mcp.getchampions.io` (OAuth sign-in, or an API key as the bearer token). See https://docs.getchampions.io/mcp."},"servers":[{"url":"https://api.getchampions.io/v1","description":"Production"},{"url":"https://app.getchampions.io/api/v1","description":"Production (same API on the app host)"}],"security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"tags":[{"name":"Workspace","description":"Who you are, credits and settings"},{"name":"Contacts","description":"The people you track. Add them with a LinkedIn URL and Champions keeps watching."},{"name":"Accounts","description":"The companies in your CRM (customers, churned, lost) that contacts belong to"},{"name":"Changes","description":"Detected job changes"},{"name":"Plays","description":"What to do about a change: direct, referral, watch, promotion"},{"name":"ICP","description":"Account and contact fit rules"},{"name":"Runs","description":"Refresh runs that check tracked profiles"},{"name":"Webhooks","description":"Push notifications for new plays, changes and runs"}],"paths":{"/me":{"get":{"tags":["Workspace"],"summary":"Who am I","description":"Workspace, credential scopes and credit balance for the token in use.","operationId":"getMe","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/credits":{"get":{"tags":["Workspace"],"summary":"Credit balance and usage","description":"Balance, per-check price, this month's usage and the estimated monthly burn at the current cadence.","operationId":"getCredits","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Credits"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/settings":{"get":{"tags":["Workspace"],"summary":"Get workspace settings","description":"Name and refresh schedule.","operationId":"getSettings","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Settings"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"tags":["Workspace"],"summary":"Update workspace settings","description":"Change the name, the refresh cadence/day/timezone, promotion tracking, alert routing or HubSpot write-back. The next refresh time is recomputed.","operationId":"updateSettings","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsPatch"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Settings"}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/contacts":{"get":{"tags":["Contacts"],"summary":"List contacts","description":"Every contact you have given us, with its tracking status and - when tracked - the profile summary (current company/title, last change).","operationId":"listContacts","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"tracking_status","in":"query","description":"Filter by tracking status","schema":{"type":"string","enum":["needs_linkedin","pending_review","ready","tracked","not_found","excluded"]}},{"name":"status","in":"query","description":"Filter by profile status (moved, promoted, …)","schema":{"type":"string","enum":["pending_baseline","same_role","promoted","moved","left","unknown","not_found"]}},{"name":"segment","in":"query","description":"CRM relationship segment","schema":{"type":"string","enum":["customer","churned","closed_lost","open_pipeline","unknown"]}},{"name":"owner","in":"query","description":"CRM owner name","schema":{"type":"string"}},{"name":"account_id","in":"query","description":"Only contacts at this account","schema":{"type":"string","format":"uuid"}},{"name":"q","in":"query","description":"Free-text search across name, company, title, email","schema":{"type":"string"}},{"name":"updated_since","in":"query","description":"ISO 8601 timestamp; only contacts/profiles updated after this","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"page":{"type":"integer"},"page_size":{"type":"integer"},"total":{"type":"integer"}},"required":["data","page","page_size","total"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Contacts"],"summary":"Add or update contacts","description":"Upsert up to 1,000 contacts per call (and, optionally, the accounts they belong to). Dedupe order: `crm_id` → LinkedIn URL → email → name + company. Contacts with a LinkedIn URL start tracking immediately (a baseline run is queued); the rest land in *Needs LinkedIn* until you send one with `PATCH /contacts/{id}`.\n\nThe body may also be a bare array of contacts.","operationId":"upsertContacts","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contacts":{"type":"array","items":{"$ref":"#/components/schemas/ContactInput"}},"accounts":{"type":"array","items":{"$ref":"#/components/schemas/AccountInput"}}},"required":["contacts"]}}}},"responses":{"202":{"description":"Accepted - contacts stored, baseline run queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertResult"}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/contacts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"Contact id (UUID)","schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Contacts"],"summary":"Get a contact","description":"Full detail: position history, detected changes, ICP fit evaluations, emails and plays.","operationId":"getContact","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDetail"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"tags":["Contacts"],"summary":"Fix or exclude a contact","description":"Send `linkedin_url` to (re)point a contact at a LinkedIn profile - this is how you resolve *Needs LinkedIn* and *Not found* - or `tracking: \"excluded\"` to stop tracking.","operationId":"patchContact","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"linkedin_url":{"type":"string","description":"LinkedIn profile URL, /in/slug or ACo… id"},"tracking":{"type":"string","enum":["excluded"]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDetail"}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"delete":{"tags":["Contacts"],"summary":"Delete a contact (GDPR)","description":"Hard-deletes the contact and, if no other contact references the same person, every snapshot, position, change, play and email we hold about them. Logged as a deletion request.","operationId":"deleteContact","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"object","properties":{"contacts":{"type":"integer"},"profiles":{"type":"integer"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/accounts":{"get":{"tags":["Accounts"],"summary":"List accounts","description":"Companies with contact counts.","operationId":"listAccounts","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"segment","in":"query","description":"Relationship segment","schema":{"type":"string","enum":["customer","churned","closed_lost","open_pipeline","unknown"]}},{"name":"q","in":"query","description":"Search name or domain","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Account"}},"page":{"type":"integer"},"page_size":{"type":"integer"},"total":{"type":"integer"}},"required":["data","page","page_size","total"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Accounts"],"summary":"Add or update accounts","description":"Upsert up to 1,000 accounts. Dedupe order: `crm_id` → domain → normalised name. The body may also be a bare array.","operationId":"upsertAccounts","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accounts":{"type":"array","items":{"$ref":"#/components/schemas/AccountInput"}}},"required":["accounts"]}}}},"responses":{"202":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertResult"}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/accounts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"Account id (UUID)","schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Accounts"],"summary":"Get an account","description":"Account with its contacts.","operationId":"getAccount","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Account"},{"type":"object","properties":{"contacts":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/changes":{"get":{"tags":["Changes"],"summary":"List job changes","description":"Detected moves, promotions, departures and unreachable profiles, newest first.","operationId":"listChanges","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"type","in":"query","description":"Change type","schema":{"type":"string","enum":["moved","promoted","title_changed","left","profile_not_found"]}},{"name":"since","in":"query","description":"Only changes detected after this ISO 8601 timestamp","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Change"}},"page":{"type":"integer"},"page_size":{"type":"integer"},"total":{"type":"integer"}},"required":["data","page","page_size","total"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/plays":{"get":{"tags":["Plays"],"summary":"List plays","description":"Plays sorted open-first, newest first. Archive plays are hidden unless you filter by `status`.","operationId":"listPlays","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"type","in":"query","description":"Play type","schema":{"type":"string","enum":["direct","referral","watch","archive","promotion","churn_risk"]}},{"name":"status","in":"query","description":"Play status","schema":{"type":"string","enum":["open","contacted","replied","meeting","not_relevant"]}},{"name":"account_fit","in":"query","description":"yes | no","schema":{"type":"string","enum":["yes","no"]}},{"name":"contact_fit","in":"query","description":"yes | no","schema":{"type":"string","enum":["yes","no"]}},{"name":"owner","in":"query","description":"CRM owner name","schema":{"type":"string"}},{"name":"segment","in":"query","description":"Relationship segment","schema":{"type":"string","enum":["customer","churned","closed_lost","open_pipeline","unknown"]}},{"name":"since","in":"query","description":"Detected on/after this date (YYYY-MM-DD)","schema":{"type":"string","format":"date"}},{"name":"q","in":"query","description":"Search person, company or title","schema":{"type":"string"}},{"name":"sort","in":"query","description":"Sort key","schema":{"type":"string","enum":["person","detected","change","relationship","afit","cfit","email","play","status","owner"]}},{"name":"dir","in":"query","description":"asc | desc","schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Play"}},"page":{"type":"integer"},"page_size":{"type":"integer"},"total":{"type":"integer"}},"required":["data","page","page_size","total"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/plays/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"Play id (UUID)","schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Plays"],"summary":"Get a play","description":"","operationId":"getPlay","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Play"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"tags":["Plays"],"summary":"Update play status or notes","description":"Move a play through open → contacted → replied → meeting, or mark it not relevant.","operationId":"updatePlay","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["open","contacted","replied","meeting","not_relevant"]},"notes":{"type":["string","null"]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Play"}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/icp":{"get":{"tags":["ICP"],"summary":"Get ICP rules","description":"Active account and contact rules with their version numbers.","operationId":"getIcp","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Icp"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"tags":["ICP"],"summary":"Replace ICP rules","description":"Send `account` and/or `contact`. Each set that actually changed becomes a new version; existing fit evaluations keep pointing at the version that produced them.","operationId":"saveIcp","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"$ref":"#/components/schemas/AccountIcpRules"},"contact":{"$ref":"#/components/schemas/ContactIcpRules"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Icp"}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/runs":{"get":{"tags":["Runs"],"summary":"List refresh runs","description":"Newest first.","operationId":"listRuns","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Run"}},"page":{"type":"integer"},"page_size":{"type":"integer"},"total":{"type":"integer"}},"required":["data","page","page_size","total"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Runs"],"summary":"Refresh now","description":"Queue a manual refresh of every tracked profile not checked in the last 24 hours. Costs one credit per profile checked - call `GET /runs/estimate` first. Returns the existing run (200) if one is already queued or running.","operationId":"createRun","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"force":{"type":"boolean","description":"Also re-check profiles fetched in the last 24h. They are served from a cache upstream and still cost one credit each, so this rarely finds anything new."}}}}}},"responses":{"200":{"description":"A run was already active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Run"}}}},"201":{"description":"Run queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Run"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/runs/estimate":{"get":{"tags":["Runs"],"summary":"Estimate a manual refresh","description":"How many profiles a refresh would check right now and what it would cost.","operationId":"estimateRun","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"profiles_due":{"type":"integer"},"profiles_recently_checked":{"type":"integer","description":"Skipped: checked within 24h"},"profiles_total":{"type":"integer"},"credits_needed":{"type":"integer"},"credit_balance":{"type":"integer"},"cost_cents":{"type":"integer"},"sufficient_credits":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/runs/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"Run id (UUID)","schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Runs"],"summary":"Get a run","description":"Poll this for progress; `totals` update as the run proceeds.","operationId":"getRun","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Run"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/runs/{id}/resume":{"parameters":[{"name":"id","in":"path","required":true,"description":"Run id (UUID)","schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Runs"],"summary":"Resume a paused run","description":"For runs paused on `client_credits` after you top up.","operationId":"resumeRun","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Run"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Not paused","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/runs/{id}/cancel":{"parameters":[{"name":"id","in":"path","required":true,"description":"Run id (UUID)","schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Runs"],"summary":"Cancel a run","description":"","operationId":"cancelRun","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Run"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Not cancellable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhook endpoints","description":"","operationId":"listWebhooks","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Webhooks"],"summary":"Create a webhook endpoint","description":"The signing `secret` is returned once. Up to 10 endpoints per workspace. Endpoints are disabled after 20 consecutive failed deliveries.","operationId":"createWebhook","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"HTTPS URL","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["play.created","contact.changed","run.completed","run.paused"]}},"description":{"type":["string","null"]}},"required":["url","events"]}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"object","properties":{"secret":{"type":"string","description":"Shown once. Use it to verify X-Champions-Signature."}}}]}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/webhooks/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"Webhook id (UUID)","schema":{"type":"string","format":"uuid"}}],"delete":{"tags":["Webhooks"],"summary":"Delete a webhook endpoint","description":"","operationId":"deleteWebhook","responses":{"204":{"description":"Deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/webhooks/{id}/test":{"parameters":[{"name":"id","in":"path","required":true,"description":"Webhook id (UUID)","schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Webhooks"],"summary":"Send a test delivery","description":"Queues a `{ ping: true }` delivery signed like a real one.","operationId":"testWebhook","responses":{"202":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"delivery_id":{"type":"integer"},"status":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/webhooks/{id}/deliveries":{"parameters":[{"name":"id","in":"path","required":true,"description":"Webhook id (UUID)","schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Webhooks"],"summary":"List deliveries","description":"Recent delivery attempts for an endpoint.","operationId":"listWebhookDeliveries","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Delivery"}},"page":{"type":"integer"},"page_size":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Workspace API key (`chp_live_…`) or OAuth access token"},"apiKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key"}},"responses":{"Unauthorized":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Credential lacks the required scope, or the workspace is suspended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"No such resource in this workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Validation":{"description":"Validation failed; see `details`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Stable machine-readable code"},"message":{"type":"string"},"details":{"description":"Validation issues or extra context"}},"required":["code","message"]}},"required":["error"]},"Me":{"type":"object","properties":{"workspace":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"}}},"auth":{"type":"object","properties":{"via":{"type":"string","enum":["api_key","oauth"]},"scopes":{"type":"array","items":{"type":"string","enum":["read","write"]}},"user_id":{"type":["string","null"],"description":"Set for OAuth tokens; null for API keys"}}},"credits":{"type":"object","properties":{"balance":{"type":"integer"},"price_per_check_cents":{"type":"integer"}}},"next_refresh_at":{"type":["string","null"],"format":"date-time"}}},"Credits":{"type":"object","properties":{"balance":{"type":"integer"},"price_per_check_cents":{"type":"integer"},"used_this_month":{"type":"object","properties":{"checks":{"type":"integer"},"emails":{"type":"integer"},"total":{"type":"integer"}}},"tracked_profiles":{"type":"integer"},"estimated_monthly_usage":{"type":"integer","description":"Credits per month at the current cadence and size"},"buy_url":{"type":"string"}}},"Settings":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"refresh_cadence":{"type":"string","enum":["weekly","biweekly","monthly","quarterly"]},"refresh_day":{"type":"integer","description":"ISO weekday 1–7 for weekly/biweekly, day of month 1–28 otherwise"},"timezone":{"type":"string","description":"IANA timezone"},"next_refresh_at":{"type":["string","null"],"format":"date-time"},"track_promotions":{"type":"boolean","description":"Promotions always produce change events; when false they create no promotion play and no alert"},"slack_channel_alerts":{"type":"boolean"},"slack_dm_owners":{"type":"boolean","description":"DM the CRM owner of the contact (matched by email) when a play is created"},"alert_play_types":{"type":"array","items":{"type":"string","enum":["direct","referral","watch","promotion","churn_risk"]}},"hubspot_writeback_enabled":{"type":"boolean"},"hubspot_writeback_mode":{"type":"string","enum":["create_new","update_existing"],"description":"create_new: new HubSpot contact at the new company and the old one flagged; update_existing: the old contact is updated in place"},"hubspot_writeback_play_types":{"type":"array","items":{"type":"string","enum":["direct","referral","watch","promotion","churn_risk"]}}}},"SettingsPatch":{"type":"object","properties":{"name":{"type":"string"},"refresh_cadence":{"type":"string","enum":["weekly","biweekly","monthly","quarterly"]},"refresh_day":{"type":"integer","minimum":1,"maximum":28},"timezone":{"type":"string","description":"IANA timezone"},"track_promotions":{"type":"boolean"},"slack_channel_alerts":{"type":"boolean"},"slack_dm_owners":{"type":"boolean"},"alert_play_types":{"type":"array","items":{"type":"string","enum":["direct","referral","watch","promotion","churn_risk"]}},"hubspot_writeback_enabled":{"type":"boolean"},"hubspot_writeback_mode":{"type":"string","enum":["create_new","update_existing"]},"hubspot_writeback_play_types":{"type":"array","items":{"type":"string","enum":["direct","referral","watch","promotion","churn_risk"]}}}},"ContactInput":{"type":"object","properties":{"first_name":{"type":"string"},"last_name":{"type":"string"},"full_name":{"type":"string","description":"Alternative to first/last; split automatically"},"company":{"type":"string","description":"Company name as in your CRM"},"title":{"type":"string"},"email":{"type":["string","null"]},"linkedin_url":{"type":["string","null"],"description":"Profile URL (https://linkedin.com/in/slug), slug, or ACo… id. Required for tracking."},"segment":{"type":["string","null"],"description":"customer | churned | closed_lost | open_pipeline; free text is normalised"},"owner":{"type":["string","null"],"description":"CRM owner name"},"crm_id":{"type":["string","null"],"description":"Your CRM record id - best dedupe key"},"account_domain":{"type":["string","null"],"description":"Links the contact to an account by domain"},"deal_stage":{"type":["string","null"]},"last_activity":{"type":["string","null"],"description":"Date (YYYY-MM-DD)"},"relationship_start":{"type":["string","null"],"description":"Date"},"relationship_end":{"type":["string","null"],"description":"Date"},"location":{"type":["string","null"],"description":"Combined 'City, State, Country'; split automatically when city/state/country are not given"},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"country":{"type":["string","null"]},"company_linkedin_url":{"type":["string","null"],"description":"Company page URL"},"company_size":{"type":["string","integer","null"],"description":"Employees; ranges like '1001-5000' keep the lower bound"},"industry":{"type":["string","null"]},"revenue":{"type":["string","number","null"],"description":"Annual revenue; '$1.2M' style strings are parsed"},"total_funding":{"type":["string","number","null"]},"company_location":{"type":["string","null"],"description":"Combined HQ location"},"company_city":{"type":["string","null"]},"company_state":{"type":["string","null"]},"company_country":{"type":["string","null"]},"custom":{"type":["object","null"],"additionalProperties":{"type":["string","number","boolean"]},"description":"Any extra fields you want stored with the contact (max 60-char keys)"}},"required":["company"]},"AccountInput":{"type":"object","properties":{"name":{"type":"string"},"domain":{"type":["string","null"]},"segment":{"type":["string","null"]},"deal_value":{"type":["number","string","null"]},"owner":{"type":["string","null"]},"crm_id":{"type":["string","null"]},"linkedin_company_url":{"type":["string","null"]},"relationship_start":{"type":["string","null"],"description":"Date"},"relationship_end":{"type":["string","null"],"description":"Date"},"industry":{"type":["string","null"]},"employees":{"type":["string","integer","null"]},"revenue":{"type":["string","number","null"]},"total_funding":{"type":["string","number","null"]},"location":{"type":["string","null"],"description":"Combined HQ location"},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"country":{"type":["string","null"]},"custom":{"type":["object","null"],"additionalProperties":{"type":["string","number","boolean"]}}},"required":["name"]},"UpsertResult":{"type":"object","properties":{"import_id":{"type":"string"},"accepted":{"type":"integer"},"rejected":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","description":"Position in the request array"},"errors":{"type":"object","additionalProperties":{"type":"string"}}}}},"accounts_accepted":{"type":"integer"},"accounts_rejected":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"errors":{"type":"object"}}}},"summary":{"type":"object","properties":{"contacts_upserted":{"type":"integer"},"accounts_upserted":{"type":"integer"},"with_linkedin":{"type":"integer"},"needs_linkedin":{"type":"integer"},"duplicates":{"type":"integer"},"profiles_created":{"type":"integer"},"profiles_linked":{"type":"integer"}}},"baseline_run":{"oneOf":[{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"}}},{"type":"null"}],"description":"The run that will take the first snapshot of new profiles"}}},"Profile":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["pending_baseline","same_role","promoted","moved","left","unknown","not_found"]},"first_name":{"type":["string","null"]},"last_name":{"type":["string","null"]},"headline":{"type":["string","null"]},"linkedin_url":{"type":["string","null"]},"current_company":{"type":["string","null"]},"current_title":{"type":["string","null"]},"current_since":{"type":["string","null"],"description":"YYYY-MM"},"last_checked_at":{"type":["string","null"],"format":"date-time"},"last_change_at":{"type":["string","null"],"format":"date-time"},"baseline_crm_mismatch":{"type":"boolean","description":"True when the first snapshot already disagreed with the CRM company"}}},"Contact":{"type":"object","properties":{"id":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"title":{"type":"string"},"company":{"type":"string","description":"Company per your CRM"},"email":{"type":["string","null"]},"linkedin_url":{"type":["string","null"]},"segment":{"type":"string","enum":["customer","churned","closed_lost","open_pipeline","unknown"]},"owner":{"type":["string","null"]},"crm_id":{"type":["string","null"]},"crm_provider":{"type":["string","null"]},"account_id":{"type":["string","null"]},"account_name":{"type":["string","null"]},"deal_stage":{"type":["string","null"]},"last_activity":{"type":["string","null"]},"relationship_start":{"type":["string","null"]},"relationship_end":{"type":["string","null"]},"tracking_status":{"type":"string","enum":["needs_linkedin","pending_review","ready","tracked","not_found","excluded"]},"tracking_reason":{"type":["string","null"],"description":"Why a LinkedIn URL was rejected"},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"country":{"type":["string","null"]},"custom":{"type":["object","null"],"additionalProperties":{"type":"string"}},"profile":{"oneOf":[{"$ref":"#/components/schemas/Profile"},{"type":"null"}],"description":"What we found on LinkedIn; null until the contact has a profile"},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"}}},"ContactDetail":{"allOf":[{"$ref":"#/components/schemas/Contact"},{"type":"object","properties":{"positions":{"type":"array","items":{"type":"object","properties":{"company":{"type":"string"},"company_linkedin_id":{"type":["string","null"]},"title":{"type":["string","null"]},"started_on":{"type":["string","null"]},"ended_on":{"type":["string","null"]},"is_current":{"type":"boolean"}}}},"changes":{"type":"array","items":{"$ref":"#/components/schemas/Change"}},"fit":{"oneOf":[{"type":"object","properties":{"account":{"oneOf":[{"$ref":"#/components/schemas/Fit"},{"type":"null"}]},"contact":{"oneOf":[{"$ref":"#/components/schemas/Fit"},{"type":"null"}]}}},{"type":"null"}]},"emails":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"status":{"type":"string"},"source":{"type":"string"},"is_primary":{"type":"boolean"},"verified_at":{"type":["string","null"],"format":"date-time"}}}},"plays":{"type":"array","items":{"$ref":"#/components/schemas/Play"}}}}]},"Fit":{"type":"object","properties":{"fit":{"type":"boolean"},"summary":{"type":"string"},"criteria":{"type":"array","items":{"type":"object","properties":{"criterion":{"type":"string"},"expected":{"type":"string"},"actual":{"type":"string"},"result":{"type":"string","enum":["match","miss","unknown"]}}}},"evaluated_at":{"type":["string","null"],"format":"date-time"}}},"Account":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"domain":{"type":["string","null"]},"segment":{"type":"string","enum":["customer","churned","closed_lost","open_pipeline","unknown"]},"lifecycle_stage":{"type":["string","null"]},"deal_value":{"type":["number","null"]},"owner":{"type":["string","null"]},"crm_id":{"type":["string","null"]},"crm_provider":{"type":["string","null"]},"linkedin_company_url":{"type":["string","null"]},"relationship_start":{"type":["string","null"]},"relationship_end":{"type":["string","null"]},"industry":{"type":["string","null"]},"employees":{"type":["integer","null"]},"revenue":{"type":["number","null"]},"total_funding":{"type":["number","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"country":{"type":["string","null"]},"custom":{"type":["object","null"]},"contacts_total":{"type":"integer"},"contacts_tracked":{"type":"integer"},"contacts_moved":{"type":"integer"},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"}}},"Change":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["moved","promoted","title_changed","left","profile_not_found"]},"profile_id":{"type":"string"},"contact_id":{"type":["string","null"]},"person":{"type":"object","properties":{"first_name":{"type":["string","null"]},"last_name":{"type":["string","null"]}}},"from_company":{"type":["string","null"]},"from_title":{"type":["string","null"]},"to_company":{"type":["string","null"]},"to_title":{"type":["string","null"]},"to_started_on":{"type":["string","null"]},"play_id":{"type":["string","null"],"description":"The sales play for this change"},"churn_play_id":{"type":["string","null"],"description":"The churn_risk play when the person left a customer account"},"detected_at":{"type":["string","null"],"format":"date-time"}}},"Play":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["direct","referral","watch","archive","promotion","churn_risk"]},"status":{"type":"string","enum":["open","contacted","replied","meeting","not_relevant"]},"contact_id":{"type":["string","null"]},"account_id":{"type":["string","null"]},"profile_id":{"type":"string"},"person":{"type":"object","properties":{"first_name":{"type":["string","null"]},"last_name":{"type":["string","null"]},"linkedin_url":{"type":["string","null"]}}},"old_company":{"type":["string","null"]},"old_title":{"type":["string","null"]},"new_company":{"type":["string","null"]},"new_title":{"type":["string","null"]},"account_fit":{"type":["boolean","null"]},"contact_fit":{"type":["boolean","null"]},"segment":{"type":"string","enum":["customer","churned","closed_lost","open_pipeline","unknown"]},"owner":{"type":["string","null"]},"account_name":{"type":["string","null"]},"email":{"type":["string","null"],"description":"Best known email for the person"},"email_status":{"type":["string","null"]},"opener":{"type":"string","description":"Suggested first line (an internal note for churn_risk)"},"notes":{"type":["string","null"]},"owner_id":{"type":["string","null"],"description":"CRM owner id of the contact"},"crm_record_id":{"type":["string","null"],"description":"HubSpot contact id once the play was pushed to the CRM"},"detected_at":{"type":["string","null"],"format":"date-time"},"status_changed_at":{"type":["string","null"],"format":"date-time"}}},"AccountIcpRules":{"type":"object","properties":{"version":{"type":"integer","const":1},"unknown_policy":{"type":"string","enum":["fail","pass"],"description":"What an unknown company field counts as"},"industries":{"type":"object","properties":{"any":{"type":"array","items":{"type":"string"}}}},"employees":{"type":"object","properties":{"min":{"type":"integer"},"max":{"type":"integer"}}},"hq":{"type":"object","properties":{"countries":{"type":"array","items":{"type":"string"}},"regions":{"type":"array","items":{"type":"string"}}}},"keywords":{"type":"object","properties":{"any":{"type":"array","items":{"type":"string"}},"fields":{"type":"array","items":{"type":"string","enum":["specialities","description","tagline","name"]}}}},"funding_stages":{"type":"array","items":{"type":"string","enum":["pre_seed","seed","series_a","series_b","series_c_plus","growth_pe","public","bootstrapped","unknown"]}},"exclude":{"type":"object","properties":{"company_ids":{"type":"array","items":{"type":"string"}},"domains":{"type":"array","items":{"type":"string"}},"name_patterns":{"type":"array","items":{"type":"string"}},"company_types":{"type":"array","items":{"type":"string"}},"current_customers":{"type":"boolean"}}}}},"ContactIcpRules":{"type":"object","properties":{"version":{"type":"integer","const":1},"title":{"type":"object","properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"seniority":{"type":"array","items":{"type":"string","enum":["c_level","vp","director","manager","ic"]}},"functions":{"type":"array","items":{"type":"string","enum":["revops","sales","marketing","customer_success","product","engineering","finance","people","operations","executive","other"]}},"min_tenure_months":{"type":"integer"}}},"Icp":{"type":"object","properties":{"account":{"type":"object","properties":{"version":{"type":"integer"},"rules":{"$ref":"#/components/schemas/AccountIcpRules"},"updated_at":{"type":["string","null"],"format":"date-time"}}},"contact":{"type":"object","properties":{"version":{"type":"integer"},"rules":{"$ref":"#/components/schemas/ContactIcpRules"},"updated_at":{"type":["string","null"],"format":"date-time"}}}}},"Run":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["baseline","scheduled","manual"]},"status":{"type":"string","enum":["queued","running","paused","completed","failed","cancelled"]},"paused_reason":{"type":["string","null"],"description":"out_of_credits | auth | upstream | client_credits | suspended"},"resume_after":{"type":["string","null"],"format":"date-time"},"created_at":{"type":["string","null"],"format":"date-time"},"started_at":{"type":["string","null"],"format":"date-time"},"finished_at":{"type":["string","null"],"format":"date-time"},"totals":{"type":"object","properties":{"items":{"type":"integer"},"processed":{"type":"integer"},"moved":{"type":"integer"},"promoted":{"type":"integer"},"left":{"type":"integer"},"not_found":{"type":"integer"},"unknown":{"type":"integer"},"plays_created":{"type":"integer"},"credits_charged":{"type":"integer"}}},"warnings":{"type":"array","items":{"type":"string"}},"error":{"type":["string","null"]}}},"Webhook":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string","enum":["play.created","contact.changed","run.completed","run.paused"]}},"description":{"type":["string","null"]},"status":{"type":"string","enum":["active","disabled"]},"failure_count":{"type":"integer"},"created_at":{"type":["string","null"],"format":"date-time"}}},"Delivery":{"type":"object","properties":{"id":{"type":"integer"},"event":{"type":"string"},"event_key":{"type":"string"},"status":{"type":"string","enum":["pending","delivered","failed"]},"attempts":{"type":"integer"},"last_status":{"type":["integer","null"]},"last_error":{"type":["string","null"]},"delivered_at":{"type":["string","null"],"format":"date-time"},"next_attempt_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":["string","null"],"format":"date-time"}}},"WebhookPayload":{"description":"Body of every webhook POST","type":"object","properties":{"id":{"type":"string","description":"Delivery id"},"event":{"type":"string","enum":["play.created","contact.changed","run.completed","run.paused"]},"event_key":{"type":"string","description":"Stable key for deduping, e.g. play:<uuid>"},"created_at":{"type":["string","null"],"format":"date-time"},"workspace_id":{"type":"string"},"data":{"type":"object","description":"A Play, Change or Run object, matching the REST shapes"}}}}}}