API reference
Every governed operation this deployment exposes, with an example call. Public developer docs — like the build guide.
Every operation is the same over MCP (the tools the Rubicon agent calls) and HTTP (POST /v1/call/<op>). Each accepts dry_run:true (the default) to validate shape without writing. Apps import the SDK same-origin from /sdk/rubicon.mjs and never hardcode a host.
Recruiting operations 31
The governed recruiting pipeline — create a project, ingest source material, define & approve criteria, discover and review prospects, run surveys, and draft outreach. Writes and decisions are attributed to the acting actor.
op_create_projectWritecreate a recruiting project
Create the project boundary that scopes source material, criteria, prospects, forms, drafts and responses.
POST /v1/call/op_create_project
{
"inputs": {
"client_name": "Example",
"name": "Example"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_ingest_source_materialWriteingest project source material
Store immutable email, note, document or transcript artifacts with hashes and provenance.
POST /v1/call/op_ingest_source_material
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"artifacts": [
{
"kind": "email",
"content": "content"
}
]
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}prep_for_define_target_criteriaPrepprepare source material for target criteria
Pure read that snapshots artifact evidence and parse warnings; it makes no targeting decision.
POST /v1/call/prep_for_define_target_criteria
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_create_target_criteriaWritecreate a target-criteria version
Persist an editable, versioned target-criteria proposal for a later approval to attest against.
POST /v1/call/op_create_target_criteria
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"criteria": [
{
"dimension": "title",
"values": [
"values"
],
"priority": "must"
}
]
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}prep_for_approve_target_criteriaPrepprepare a criteria version for approval
Pure read of the exact criteria version, source citations and prohibited-targeting flags.
POST /v1/call/prep_for_approve_target_criteria
{
"inputs": {
"criteria_version_id": "00000000-0000-0000-0000-000000000000"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_approve_target_criteriaDecisionapprove target criteria
Record an approve/reject decision on one immutable criteria version, attributed to the acting actor (human or named AI) with schema-validated evidence.
POST /v1/call/op_approve_target_criteria
{
"inputs": {
"criteria_version_id": "00000000-0000-0000-0000-000000000000",
"verdict": "approve",
"rationale": "rationale"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}prep_for_plan_lead_searchPrepprepare a lead-search plan
Compile a capability-aware Google-first query plan from approved criteria without searching.
POST /v1/call/prep_for_plan_lead_search
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"criteria_version_id": "00000000-0000-0000-0000-000000000000"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_create_search_planDecisionapprove a lead-search plan
Persist a reproducible query plan; the acting actor's acceptance or edits are recorded as an attributed, evidence-backed decision.
POST /v1/call/op_create_search_plan
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"criteria_version_id": "00000000-0000-0000-0000-000000000000",
"provider": {
"kind": "google",
"search_mode": "web"
},
"query_variants": [
{
"query": "query"
}
]
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_discover_leadsExternaldiscover prospects
Execute an approved lead-search plan. Google web search is the only enabled MVP provider.
POST /v1/call/op_discover_leads
{
"inputs": {
"search_plan_id": "00000000-0000-0000-0000-000000000000"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}prep_for_review_prospectsPrepprepare prospects for review
Deduplicate and annotate prospects with evidence, suppression state and criterion matches.
POST /v1/call/prep_for_review_prospects
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_review_prospectsDecisionreview prospects
Record a yes/maybe/no decision per prospect, attributed to the acting actor with evidence. No deletes: rejected prospects remain attributable.
POST /v1/call/op_review_prospects
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"decisions": [
{
"prospect_id": "00000000-0000-0000-0000-000000000000",
"verdict": "yes",
"rationale": "rationale"
}
]
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_find_potential_participantsExternalfind potential participants (Exa)
Search Exa for LinkedIn people (+ the existing panel), dedupe by identity, store each in the global panel, link them to the project as 'candidate', and RANK by a relevance score — Exa's within-query rank DOMINATES (its top-10 surface at the top; each result carries `rank` + `source_query`), keyword fit is a secondary steer, rank-less panel token-matches are capped below clean top Exa hits, and retired/student/homonym penalties sink noise (each candidate carries `flags` for the reviewer). BEST-USE PLAYBOOK: (1) write each query as a PERSON not a topic — 'master plumbers who install digital mixing valves', not 'digital mixing valves'; (2) Exa caps ~100/query and does NOT paginate, so get volume from MANY facet-varied queries — fan a broad persona by STATE/DISTRICT, a NICHE persona by descriptive TITLE — and the op dedupes; (3) use ~25 results/query (default), not 100 — relevance is front-loaded; (4) pass exclude_terms for known homonyms. Expect ~50-70% strong matches, so ALWAYS review (candidate→matched) before outreach. Returns full profiles + real Exa cost.
POST /v1/call/op_find_potential_participants
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"queries": [
"queries"
]
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_resolve_participant_contactExternalresolve participant work emails
Resolve work emails for one or more recruits IN PARALLEL through a gated pipeline: Exa grounded answer (exact published email + the company's DOCUMENTED format + mail domain, assembled deterministically when no exact address exists) → hard gates (MX/deliverability, no role accounts like info@, no freemail; a gate kill returns unresolved with the reason in `flags`) → free SMTP RCPT verification (never sends; auto-disabled where port 25 is blocked). `confidence` is COMPUTED from `checks` (mx/name_match/format_consistent/...), never the LLM's self-report; `corroborated` means the local part matches THIS person's name. Cached unless force:true. Returns per-recruit results + total cost. Run it ON DEMAND for the people you're actually pursuing. An evidence-only Parallel fallback (~$0.005/run) automatically covers anyone the fast pipeline leaves unresolved.
POST /v1/call/op_resolve_participant_contact
{
"inputs": {
"recruit_ids": [
"recruit_ids"
]
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_set_participant_statusDecisionmatch / maybe / reject participants for a project
Record a researcher's per-participant verdict for ONE project: matched, maybe or rejected (+ optional comment), attributed to the acting actor. This is the approve-the-matches gate. Reversible — call again to change a verdict. A rejection is scoped to this project; the recruit stays in the panel for others.
POST /v1/call/op_set_participant_status
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"updates": [
{
"recruit_id": "00000000-0000-0000-0000-000000000000",
"status": "matched"
}
]
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_add_outreach_draftWritesave outreach drafts for participants
Save one outreach draft (subject + body + optional link) for a batch of participants in a project. The text is a MERGE TEMPLATE — tokens like {{first_name}}, {{company}}, {{title}}, {{link}} are filled per recruit from their profile; a token with no value is left blank and reported. One draft per (project, recruit); re-saving replaces it. It never sends mail.
POST /v1/call/op_add_outreach_draft
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"recruit_ids": [
"recruit_ids"
],
"subject": "subject",
"body_text": "body_text"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}prep_for_configure_qualificationPrepprepare a short qualification form
Build a candidate one-to-three-question form context and renderer feasibility assessment.
POST /v1/call/prep_for_configure_qualification
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"criteria_version_id": "00000000-0000-0000-0000-000000000000",
"transport": "hosted_link"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_set_qualification_formDecisionapprove a qualification form
Create an immutable form version whose approval is attributed to the acting actor with schema-validated evidence. Hosted links are MVP; Gmail AMP remains gated.
POST /v1/call/op_set_qualification_form
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"title": "Example",
"transport": "hosted_link",
"questions": [
{
"prompt": "prompt",
"type": "single_select"
}
]
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}prep_for_draft_outreachPrepprepare approved prospects for outreach drafting
Return review-approved prospects, form state, suppression flags and prior drafts/replies.
POST /v1/call/prep_for_draft_outreach
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"form_id": "00000000-0000-0000-0000-000000000000"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_draft_outreachWritesave outbound email drafts
Persist versioned email content tied to a prospect and qualification form; it never sends mail.
POST /v1/call/op_draft_outreach
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"form_id": "00000000-0000-0000-0000-000000000000",
"drafts": [
{
"prospect_id": "00000000-0000-0000-0000-000000000000",
"subject": "subject",
"body_text": "body_text"
}
]
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}prep_for_approve_outreachPrepprepare outbound drafts for approval
Return the exact content, recipient provenance, suppression state and form renderer status.
POST /v1/call/prep_for_approve_outreach
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_approve_outreachDecisionapprove outbound drafts
Record an approve/reject decision for every outward-facing message, attributed to the acting actor with schema-validated evidence.
POST /v1/call/op_approve_outreach
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"decisions": [
{
"draft_id": "00000000-0000-0000-0000-000000000000",
"verdict": "approve",
"rationale": "rationale"
}
]
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}capture_hosted_form_submissionOpcapture a hosted-form response
Narrow public endpoint using an opaque, expiring, one-time delivery token. It is not a general MCP browser call.
POST /v1/call/capture_hosted_form_submission
{
"inputs": {},
"dry_run": true
}ingest_gmail_replyOpingest a targeted Gmail reply
Webhook/poll worker ingestion keyed by Gmail message ID; mailbox-wide trawling is out of scope.
POST /v1/call/ingest_gmail_reply
{
"inputs": {
"delivery_id": "00000000-0000-0000-0000-000000000000",
"gmail_message_id": "00000000-0000-0000-0000-000000000000"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}prep_for_review_responsesPrepprepare responses for researcher review
Correlate form and targeted Gmail replies to prospects, drafts and qualification versions.
POST /v1/call/prep_for_review_responses
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_triage_responsesDecisiontriage qualification responses
Record a qualify/decline/follow-up/opt-out decision, attributed to the acting actor with evidence. Qualified people are handed to Vidlet for scheduling.
POST /v1/call/op_triage_responses
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"decisions": [
{
"response_id": "00000000-0000-0000-0000-000000000000",
"verdict": "qualified",
"rationale": "rationale"
}
]
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_create_surveyWritecreate a survey
Create a named survey inside a project. A project may hold many surveys; the survey is the boundary reusable questions attach to.
POST /v1/call/op_create_survey
{
"inputs": {
"project_id": "00000000-0000-0000-0000-000000000000",
"name": "Example"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_create_survey_questionWriteadd a reusable survey question
Add a reusable question primitive to a survey — a prompt, an ordered number, a declared answer_type and a free-form answer_mode (text box, slider, date-range, dropdown — anything) plus arbitrary config. Call repeatedly to build the survey.
POST /v1/call/op_create_survey_question
{
"inputs": {
"survey_id": "00000000-0000-0000-0000-000000000000",
"prompt": "prompt",
"question_number": 1,
"answer_type": "answer_type",
"answer_mode": "answer_mode",
"required": true
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_set_survey_statusWriteopen or close a survey
Set a survey active or closed. A closed survey rejects new questions, embeds and answers; reopen it to resume. Freezes a survey once you start fielding it.
POST /v1/call/op_set_survey_status
{
"inputs": {
"survey_id": "00000000-0000-0000-0000-000000000000",
"status": "active"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_publish_surveyWritepublish a survey to a hosted link
Mint (or return) the survey's stable Rubicon-hosted public link — no email required. Anyone with the link fills the hosted form (or the survey's custom page) and answers stream in with their self-entered email. regenerate:true revokes the old link and mints a new one.
POST /v1/call/op_publish_survey
{
"inputs": {
"survey_id": "00000000-0000-0000-0000-000000000000",
"expires_in_days": 90,
"regenerate": false
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_set_survey_pageWriteset a bespoke survey page
Attach a custom-designed HTML page to a survey; Rubicon hosts it at the survey's public/form links in place of the default renderer. Contract: the page submits to the RELATIVE URL 'form-submit' with fields q<question_number> (+ respondent_email on shared links). Empty page_html clears back to the default.
POST /v1/call/op_set_survey_page
{
"inputs": {
"survey_id": "00000000-0000-0000-0000-000000000000"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}op_answer_surveyOpanswer a survey question
PUBLIC ingress: anyone (a hosted form or an embedded email link) may submit one validated answer, which streams into the dedicated survey-answers store. Intentionally outside the actor-auth model; not callable as an MCP tool.
POST /v1/call/op_answer_survey
{
"inputs": {
"survey_id": "00000000-0000-0000-0000-000000000000",
"question_number": 1,
"answer": "example"
},
"idempotency_key": "REPLACE-WITH-A-UNIQUE-KEY-PER-CALL",
"dry_run": true
}App building & platform 16
The company-agnostic lifecycle every Rubicon app is built and run on: deploy from source, patch in place, roll back, inspect activity, and read or write durable app state.
list_appsReadList the apps you can see — each with its live URL, status and version.
List the apps you can see — each with its live URL, status and version.
POST /v1/call/list_apps
{
"inputs": {},
"dry_run": true
}get_appReadOne app's metadata: status, active version, owner and description.
One app's metadata: status, active version, owner and description.
POST /v1/call/get_app
{
"inputs": {},
"dry_run": true
}get_app_contextReadEverything an editor needs before changing an app: source, contract, recent activity.
Everything an editor needs before changing an app: source, contract, recent activity.
POST /v1/call/get_app_context
{
"inputs": {},
"dry_run": true
}get_app_sourceReadRead an app's current source bundle (client + server + manifest).
Read an app's current source bundle (client + server + manifest).
POST /v1/call/get_app_source
{
"inputs": {},
"dry_run": true
}get_app_activityReadAn app's recent governed calls — the audit trail behind what it did.
An app's recent governed calls — the audit trail behind what it did.
POST /v1/call/get_app_activity
{
"inputs": {},
"dry_run": true
}list_app_versionsReadEvery deployed version of an app, newest first (for rollback).
Every deployed version of an app, newest first (for rollback).
POST /v1/call/list_app_versions
{
"inputs": {},
"dry_run": true
}deploy_app_sourceWriteCreate or replace an app from source; the build typechecks against this API.
Create or replace an app from source; the build typechecks against this API.
POST /v1/call/deploy_app_source
{
"inputs": {},
"dry_run": true
}update_app_sourceWritePatch an existing app in place and cut a new version.
Patch an existing app in place and cut a new version.
POST /v1/call/update_app_source
{
"inputs": {},
"dry_run": true
}set_app_statusWriteMove an app between development / beta / production.
Move an app between development / beta / production.
POST /v1/call/set_app_status
{
"inputs": {},
"dry_run": true
}rollback_appWriteInstantly restore a previous version of an app.
Instantly restore a previous version of an app.
POST /v1/call/rollback_app
{
"inputs": {},
"dry_run": true
}promote_app_versionWriteMake an app's staged candidate the live version (atomic compare-and-set).
Make an app's staged candidate the live version (atomic compare-and-set).
POST /v1/call/promote_app_version
{
"inputs": {},
"dry_run": true
}discard_app_versionWriteDrop an app's staged candidate without touching the live version.
Drop an app's staged candidate without touching the live version.
POST /v1/call/discard_app_version
{
"inputs": {},
"dry_run": true
}exercise_appWriteDrive an app's own routes server-side to prove it works end-to-end.
Drive an app's own routes server-side to prove it works end-to-end.
POST /v1/call/exercise_app
{
"inputs": {},
"dry_run": true
}capsule_state_getReadRead a value from an app's durable key/value state.
Read a value from an app's durable key/value state.
POST /v1/call/capsule_state_get
{
"inputs": {},
"dry_run": true
}capsule_state_setWriteWrite a value into an app's durable key/value state.
Write a value into an app's durable key/value state.
POST /v1/call/capsule_state_set
{
"inputs": {},
"dry_run": true
}list_modelsReadThe inference models available to apps, plus the current default.
The inference models available to apps, plus the current default.
POST /v1/call/list_models
{
"inputs": {},
"dry_run": true
}