{"openapi":"3.1.0","info":{"title":"dogo API","description":"The dogo executive-search loop — plan, source, score, enrich, sequence. All endpoints require a Bearer API key scoped to your org. Every tool is also available via MCP at /api/mcp.","version":"0.1.0"},"servers":[{"url":"https://dogoapp.ai","description":"This server"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Org-scoped API key. Generate one in Settings → API keys."}}},"paths":{"/api/missions":{"get":{"operationId":"list_missions","summary":"List missions","description":"Return all missions for the org, most recent first.","security":[{"bearerAuth":[]}],"tags":["Mission"],"responses":{"200":{"description":"Array of mission objects"},"401":{"description":"Unauthorized"}}},"post":{"operationId":"create_mission_rest","summary":"Create mission","description":"Create a new mission. Alias for the create_mission tool.","security":[{"bearerAuth":[]}],"tags":["Mission"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string"},"roleSummary":{"type":"string"},"brief":{"type":"string"}}}}}},"responses":{"201":{"description":"Created mission"},"401":{"description":"Unauthorized"}}}},"/api/missions/{id}":{"get":{"operationId":"get_mission","summary":"Get mission","description":"Return a single mission by id.","security":[{"bearerAuth":[]}],"tags":["Mission"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Mission object"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"}}}},"/api/missions/{id}/candidates":{"get":{"operationId":"list_candidates","summary":"Ranked candidates","description":"Return the ranked longlist for a mission. Gated candidates (must-have miss) are included and flagged, not hidden.","security":[{"bearerAuth":[]}],"tags":["Longlist"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","maximum":500}},{"name":"includeGated","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Array of ranked candidates with person + score"},"401":{"description":"Unauthorized"}}}},"/api/missions/{id}/criteria":{"get":{"operationId":"list_criteria","summary":"Mission criteria","description":"Return the weighted must/nice criteria for a mission, in display order.","security":[{"bearerAuth":[]}],"tags":["Mission"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Array of criterion objects"},"401":{"description":"Unauthorized"}}}},"/api/pool":{"get":{"operationId":"list_pool","summary":"Search talent pool","description":"Search the org talent pool by name, title, or company. Returns up to 50 results by default.","security":[{"bearerAuth":[]}],"tags":["Talent Pool"],"parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Search query"},{"name":"limit","in":"query","schema":{"type":"integer","maximum":100}}],"responses":{"200":{"description":"Array of pool entries"},"401":{"description":"Unauthorized"}}}},"/api/tools/create_mission":{"post":{"operationId":"create_mission","summary":"create mission","description":"Create a new mission (search) for the org and return its id. Call this first when the consultant wants to start a new search. Pass a working title and optionally a role summary or brief if you already have them — both can be filled in later with update_mission. The returned missionId is what all subsequent tools need.","security":[{"bearerAuth":[]}],"tags":["Mission"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1},"roleSummary":{"type":"string"},"brief":{"type":"string"}},"required":["title"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/update_mission":{"post":{"operationId":"update_mission","summary":"update mission","description":"Set this mission’s title and brief once you understand the search. The mission already exists — this fills it in. Put the client/company name and context in roleSummary or brief. When recruiting FOR a company, set offLimits to the companies whose current employees must be excluded — the hiring client + its group brands (research them) + any do-not-poach firms. Setting offLimits re-gates the existing longlist immediately (current employees → excluded).","security":[{"bearerAuth":[]}],"tags":["Mission"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"missionId":{"type":"string"},"title":{"type":"string"},"roleSummary":{"type":"string"},"brief":{"type":"string"},"offLimits":{"type":"array","items":{"type":"string"}}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/research":{"post":{"operationId":"research","summary":"research","description":"Resolve what the brief refers to, against current web sources, with citations. Use BEFORE sourcing when the brief names something you cannot enumerate confidently or that may be out of date — a program, index, ranking, or cohort (\"the Next40 startups\", \"the FT120\"), \"companies like X\", \"competitors of Y\". A LinkedIn profile won’t carry that label, so resolve it into the concrete company names/facts it stands for, then fold those into the mission brief and criteria. Returns a synthesized answer + the source URLs (show them).","security":[{"bearerAuth":[]}],"tags":["Research"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","minLength":3}},"required":["query"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/read_url":{"post":{"operationId":"read_url","summary":"read url","description":"Read the main text of one web page — a job spec or list the consultant pasted, an official program page, a company page. Use to ground details from a specific source you already have.","security":[{"bearerAuth":[]}],"tags":["Research"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"}},"required":["url"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/draft_mission_plan":{"post":{"operationId":"draft_mission_plan","summary":"draft mission plan","description":"Turn the brief into a reviewable sourcing plan and weighted must/nice criteria for the consultant to edit. Operates on the current mission.","security":[{"bearerAuth":[]}],"tags":["Sourcing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"missionId":{"type":"string"},"brief":{"type":"string"}},"required":["brief"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/preview_sourcing":{"post":{"operationId":"preview_sourcing","summary":"preview sourcing","description":"Show the exact search query and 5 sample candidate profiles before committing to the full run. Instant and cheap — one API call, no credits charged, no DB state change. Call this BEFORE run_sourcing so the consultant can confirm the search is aimed at the right pool. If the samples look wrong, update the mission brief and preview again.","security":[{"bearerAuth":[]}],"tags":["Sourcing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"missionId":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/run_sourcing":{"post":{"operationId":"run_sourcing","summary":"run sourcing","description":"Source and score candidates for the current mission. Call this once the consultant is happy with the criteria and has said go — it spends time and money on a real search. Returns immediately; results stream into the longlist. Re-runnable to expand it.","security":[{"bearerAuth":[]}],"tags":["Sourcing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"missionId":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/expand_similar":{"post":{"operationId":"expand_similar","summary":"expand similar","description":"Find more candidates like a specific strong one — similarity search from a person (by their name as it appears in the longlist, or a LinkedIn URL) → similar profiles, scored into the longlist. Use when the consultant says \"find more like <name>\". (Sourcing already auto-expands from the top hits; this is for a named person on demand.)","security":[{"bearerAuth":[]}],"tags":["Sourcing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"missionId":{"type":"string"},"seedName":{"type":"string"},"seedUrl":{"type":"string","format":"uri"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/expand_websearch":{"post":{"operationId":"expand_websearch","summary":"expand websearch","description":"Run a DEEPER web search to widen the longlist — an deep web search pass validated against the mission’s must-haves, a different recall source than the standard sourcing. Net-new people are scored and gated by our own engine (off-limits still enforced) and stream into the longlist. Costs more and takes a couple of minutes, so offer it when the field is thin or she wants more coverage — don’t run it unprompted. Results land on their own; hand off like with run_sourcing.","security":[{"bearerAuth":[]}],"tags":["Sourcing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"missionId":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/get_ranked_candidates":{"post":{"operationId":"get_ranked_candidates","summary":"get ranked candidates","description":"Read the ranked longlist for the current mission once, to inform your spoken read — the full gradient, gated (must-have miss) candidates flagged, not hidden. The consultant already sees the live table beside the chat, so do NOT poll this to watch results load and do NOT retype the list back to her; pull it a single time once results have landed, then summarize.","security":[{"bearerAuth":[]}],"tags":["Longlist"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"missionId":{"type":"string"},"limit":{"type":"integer","exclusiveMinimum":true,"minimum":0,"maximum":200},"includeGated":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/shortlist_candidates":{"post":{"operationId":"shortlist_candidates","summary":"shortlist candidates","description":"Add or remove candidates from the shortlist (the set the consultant will pursue). Use the candidate ids from get_ranked_candidates. The consultant can also do this herself in the UI; suggest, don’t over-reach.","security":[{"bearerAuth":[]}],"tags":["Longlist"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"missionId":{"type":"string"},"candidateIds":{"type":"array","items":{"type":"string"},"minItems":1},"action":{"type":"string","enum":["add","remove"],"default":"add"}},"required":["candidateIds"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/run_custom_enrichment":{"post":{"operationId":"run_custom_enrichment","summary":"run custom enrichment","description":"Answer a freeform question about each SHORTLISTED candidate (only the shortlist can be enriched). Give a short label, the question as a prompt (use {{name}}/{{title}}/{{company}} to reference the person), and whether it needs the web. Example: label \"Aerospace cert\", prompt \"Does {{name}} hold an aerospace or defense security clearance/certification?\", web true. Runs across the shortlist and writes a value per candidate (visible in their detail panel).","security":[{"bearerAuth":[]}],"tags":["Enrichment"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"missionId":{"type":"string"},"label":{"type":"string"},"prompt":{"type":"string"},"outputType":{"type":"string","enum":["text","url","number"]},"web":{"type":"boolean"}},"required":["label","prompt"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/generate_outreach":{"post":{"operationId":"generate_outreach","summary":"generate outreach","description":"Draft personalized first-touch outreach (email + LinkedIn) for the SHORTLIST — grounded in each person’s background and why they fit. This resolves the shortlist itself — just call it; you do NOT need to look up or pass who’s shortlisted first (optionally pass candidate ids to narrow it). Returns how many it generated; if 0, nothing’s shortlisted yet. The consultant reviews/edits before anything is drafted/sent (email → Gmail draft, LinkedIn → copy-and-open); nothing is sent automatically. Re-runnable to regenerate.","security":[{"bearerAuth":[]}],"tags":["Outreach"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"missionId":{"type":"string"},"candidateIds":{"type":"array","items":{"type":"string"}}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/enrich_contacts":{"post":{"operationId":"enrich_contacts","summary":"enrich contacts","description":"Find verified email + phone for the SHORTLIST (via contact enrichment provider, the org’s connected key). This resolves the shortlist itself — just call it; you do NOT need to look up or pass who’s shortlisted first (optionally pass candidate ids to narrow it). Skips anyone who already has the contact details an active channel needs. Returns how many it started; if 0, nothing shortlisted needs it. Runs in the background, fills contacts onto each person (reused across missions). Needed before an email draft. Costs credits — run it when she wants to reach out.","security":[{"bearerAuth":[]}],"tags":["Enrichment"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"missionId":{"type":"string"},"candidateIds":{"type":"array","items":{"type":"string"}}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/add_to_pool":{"post":{"operationId":"add_to_pool","summary":"add to pool","description":"Add a specific person to the firm's talent pool — a referral, known contact, or candidate the consultant mentions. LinkedIn URL is REQUIRED: it is the dedup key and enables automatic profile enrichment (title, company, career history) automatically. Ask the consultant for the URL if they haven't provided one. Tags and notes are optional firm-level context.","security":[{"bearerAuth":[]}],"tags":["Talent Pool"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fullName":{"type":"string"},"linkedinUrl":{"type":"string","format":"uri"},"currentTitle":{"type":"string"},"currentCompany":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"notes":{"type":"string"}},"required":["linkedinUrl"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}},"/api/tools/search_talent_pool":{"post":{"operationId":"search_talent_pool","summary":"search talent pool","description":"Search the firm’s talent pool — people already in dogo from past searches (enriched once, reused across missions). Use to answer \"who do we already know at X / for this kind of role\". Read-only, lexical match on name/title/company. Returns a compact list with how many searches each has been in.","security":[{"bearerAuth":[]}],"tags":["Talent Pool"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string"},"limit":{"type":"integer","exclusiveMinimum":true,"minimum":0,"maximum":100}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","description":"Tool result (shape varies per tool)"}}}},"400":{"description":"Bad request / validation error"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Unknown tool"},"501":{"description":"Not yet implemented"}}}}}}