Developer reference · v1

KR.S API & MCP

Developer and coding-agent reference for authenticated CRM integrations.

Quick start

Base URL: https://krs.studio. API v1 and MCP are two separate authenticated interfaces. Use prospect intake for researched companies; lead intake is for actual enquiries. This guide is public, but it does not grant access to CRM data.

curl https://krs.studio/api/public/v1/ping \
  -H "X-API-Key: <YOUR_API_KEY>"

# Response: { "ok": true, "time": "<ISO timestamp>" }

Examples use fictional contacts and placeholder credentials. A submission writes a real record: use only approved test contacts. There is no dry-run endpoint.

Authentication & limits

Create an API key in Admin → API & integrations. Copy it once and keep it in your agent's secret store. Keys are stored hashed and can be revoked in admin; never place keys in prompts, URLs, source code or logs.

X-API-Key: <YOUR_API_KEY>
# Alternatively:
Authorization: Bearer <YOUR_API_KEY>
Content-Type: application/json

API keys created in admin include leads:write and prospects:write. Both prospect methods enforce prospects:write. Leads and ping currently validate the key without an additional scope check. An API key is not an MCP OAuth token.

The API rate limit is 60 requests per minute per key. Use serial batches, wait at least 60 seconds after 429, and retry transient failures with bounded exponential backoff. Do not assume an HTTP 200 means every item was saved.

Prospect intake & results

POST /api/public/v1/prospects

Send one prospect or an object containing a prospects array of 1–50 items. Only company is required; supply verified contact information, evidence and fit reasoning for useful review. All other fields are optional; fields except lang also accept null. Strings are trimmed.

FieldContract
companyRequired string, 1–160 characters
websiteURL string, up to 300 characters
industry / cityStrings, up to 120 characters each
contact_name / contact_roleStrings, up to 120 characters each
emailValid work email, up to 160 characters
phoneString, up to 40 characters
linkedinURL string, up to 300 characters
descriptionWhat the company does; up to 2,000 characters
fit_reason / contact_reasonWhy KR.S fits / why contact now; up to 1,500 characters each
suggested_serviceString, up to 160 characters
confidenceInteger 0–100; do not present guesses as verified facts
source_urlEvidence URL, up to 500 characters
langcs or en; optional
curl -X POST https://krs.studio/api/public/v1/prospects \
  -H "X-API-Key: <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"prospects":[{
    "company":"Example Company",
    "website":"https://example.com",
    "email":"research-test@example.com",
    "description":"A fictional company used in this example.",
    "fit_reason":"Replace with evidence relevant to KR.S.",
    "contact_reason":"Replace with a verified reason to reach out now.",
    "source_url":"https://example.com",
    "lang":"cs"
  }]}'

Intake creates pending prospects; it never sends email. Matching email, active prospect domain, existing lead or a suppression entry can cause a skip. Compare submitted count with created.length + skipped.length and inspect each reason. On a request failure, some earlier rows may already exist; reconcile before retrying.

{
  "success": true,
  "created": [{ "id": "<prospect UUID>", "company": "Example Company" }],
  "skipped": []
}
# Possible skip reasons include duplicate_email, duplicate_domain,
# already_a_lead and blocklisted.

GET /api/public/v1/prospects

Returns aggregate outreach results: funnel counts and performance breakdowns, not a list of company profiles. Requires the same prospects:write scope. Use MCP list_prospects to read prospect summaries.

Lead intake

POST /api/public/v1/leads

For genuine inbound enquiries from forms, Meta lead ads or approved imports. Send one lead or {"leads": […]}, with 1–200 items. Leads are merged by email. Research companies should not be submitted here.

Communication warning: auto_reply defaults to true and can trigger Dot's first response. Set auto_reply to false when importing without sending or testing the intake.

FieldContract
name / emailRequired: name 1–120 characters; valid email up to 160
phoneOptional string, up to 40 characters
langcs or en; defaults to cs
sourcemeta_lead_ad (default), web_contact, dot, manual, api, other
source_detail / interestOptional strings, up to 160 characters each
external_idOptional external reference, up to 120 characters
messageOptional string, up to 4,000 characters
preferred_dateOptional YYYY-MM-DD string
answersFlat object: keys ≤80 characters; string ≤2,000, number, boolean or null values
auto_replyBoolean; defaults to true. Set false for intake without automatic replies.
curl -X POST https://krs.studio/api/public/v1/leads \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"name":"Example Contact","email":"intake-test@example.com","source":"api","auto_reply":false}'

# Response:
{"success":true,"created":1,"merged":0,"errors":[],"totalErrors":0}

Batch responses may be partially successful. Review errors (zero-based input index, code and message) and totalErrors. Require created + merged + totalErrors to equal the number submitted. Do not blindly resubmit an entire auto-reply batch after an ambiguous failure.

Make.com / Meta lead ads

Use Facebook Lead Ads → Watch Leads, then an HTTP POST with JSON. Map name and email, phone, form name to source_detail, the Meta lead identifier to external_id, and other form answers to answers. Set source to meta_lead_ad and explicitly choose auto_reply.

MCP for coding & research agents

Server URL: https://krs.studio/mcp. Configure a remote Streamable HTTP MCP connection in your assistant. Use its OAuth discovery and sign in as an authorized KR.S administrator; approve the connection. Each tool acts as the caller and checks admin access. No anonymous CRM access and no API-key authentication on MCP.

OAuth resource discovery is available at https://krs.studio/.well-known/oauth-protected-resource. Let your MCP client follow its metadata; do not hardcode issuer infrastructure or paste session tokens.

# Required HTTP headers for MCP POST transport:
Accept: application/json, text/event-stream
Content-Type: application/json

# After OAuth connection, use the client's tool calls:
list_prospects({"status":"pending","limit":50,"offset":0})
submit_prospects({"prospects":[{"company":"Example Company","website":"https://example.com"}]})
get_outreach_results({})
FieldContract
submit_prospects1–25 prospect objects using the profile contract above. Returns created/skipped; nothing is emailed.
list_prospectsOptional status, limit (1–100; default 50), offset (≥0; default 0). Returns prospect summaries and next_offset; continue until null.
get_outreach_resultsNo arguments. Returns aggregate funnel and reply performance by industry, city and service.

Valid status filters: pending, approved, drafted, queued, sent, replied, meeting, won, lost, rejected. Summaries contain id, company, domain, industry, city, email, status, reply_class, confidence and created_at; there is no full-profile detail tool currently.

These tools cannot approve prospects, change sending settings or send emails. Only submit real research under the owner's instructions; do not invent contacts or evidence. Agent-visible data must stay within the authorized workflow.

Research → approval → outreach → learning

  1. The owner's Hermes/Claude agent researches the specified market and records verified evidence and fit reasons.
  2. Submit through prospect API or MCP; reconcile created/skipped results. The admin reviews pending companies and explicitly approves suitable prospects.
  3. Dot prepares a customized draft. The admin reviews the draft and queues it under the configured sending policy.
  4. Only the scheduled outreach queue sends messages, with idempotency and suppression checks; intake and MCP calls never send.
  5. Replies are classified and linked to the CRM. Where automation is enabled, Dot responds within its policy; requested or necessary human intervention produces an admin alert and email.
  6. Record meeting/won/lost outcomes in admin, then use aggregate results to refine future research. A reply is not the same as a successful sale.

A queued message is not proof of delivery. Check actual send state, errors and replies in admin. Public documentation does not guarantee a particular connector is configured or that this revision has been published.

Errors & troubleshooting

FieldContract
200Inspect batch counts and per-row errors/skips. Ping confirms authentication, not successful intake.
400 bad_requestInvalid JSON, invalid field or batch limit exceeded. Correct input before retrying.
401 unauthorizedMissing, invalid or revoked API key; on MCP, reconnect through OAuth.
403 forbiddenProspect API key lacks prospects:write, or MCP caller lacks admin access.
429 rate_limitedWait at least 60 seconds; use serial batches and bounded backoff.
5xx / timeoutReconcile potentially saved rows before retrying; do not turn an ambiguous result into duplicate outreach.
MCP 406Send Accept: application/json, text/event-stream alongside Content-Type: application/json.

Never include credentials or customer data in shared diagnostic logs. The admin API page owns key management; this public guide contains only contracts and fictional examples.