Developer documentation
Create and update contacts, read your agents and call outcomes, and receive signed webhooks when things happen. Everything below is generated from the same specification the API serves, so it stays in step with what is actually deployed.
Machine-readable spec: /api/v1/openapi.json
Create a key in the dashboard under Settings → Developers, then confirm it works. The key is shown once — store it somewhere safe.
curl https://www.getsyou.ai/api/v1/ping \
-H "Authorization: Bearer $GETSYOU_API_KEY"
# {"ok":true,"organization":"Your Company","scopes":["contacts:write"]}const res = await fetch("https://www.getsyou.ai/api/v1/contacts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.GETSYOU_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
first_name: "Ada",
phone: "+15551234567",
source: "website-form",
consent: { sms: true },
}),
});
const contact = await res.json();import os, uuid, requests
requests.post(
"https://www.getsyou.ai/api/v1/contacts",
headers={
"Authorization": f"Bearer {os.environ['GETSYOU_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"first_name": "Ada",
"phone": "+15551234567",
"source": "website-form",
"consent": {"sms": True},
},
timeout=30,
)Send your key as a bearer token. It is never accepted in a query string, because query strings end up in access logs, proxy logs and browser history.
Every response carries an X-Request-Id header. Quote it if you need to ask us about a specific request.
Authorization: Bearer gy_live_...Each key carries an explicit list of permissions. A key with no scopes can authenticate but do nothing — grant only what the integration needs.
| Scope | Allows |
|---|---|
agents:read | View agents |
contacts:read | Read contacts |
contacts:write | Create and update contacts |
calls:read | Read call status and outcomes |
transcripts:read | Read call transcripts |
webhooks:read | View webhook endpoints and deliveries |
webhooks:write | Create, update and disable webhooks |
applications:write | Report application outcomes |
benchmark:read | Read your own benchmark score and audit |
calls:create | Start calls (not yet available) |
| Endpoint | Description |
|---|---|
GET /api/v1/ping | Verify a key |
GET /api/v1/agents | List agents — requires agents:read |
GET /api/v1/agents/{agent_id} | Retrieve an agent — requires agents:read |
GET /api/v1/contacts | List contacts — requires contacts:read |
POST /api/v1/contacts | Create a contact — requires contacts:write |
GET /api/v1/contacts/{contact_id} | Retrieve a contact — requires contacts:read |
PATCH /api/v1/contacts/{contact_id} | Update a contact — requires contacts:write |
POST /api/v1/contacts/upsert | Create or update a contact — requires contacts:write |
GET /api/v1/calls | List calls — requires calls:read |
GET /api/v1/calls/{call_id} | Retrieve a call — requires calls:read |
GET /api/v1/calls/{call_id}/transcript | Retrieve a call transcript — requires transcripts:read |
POST /api/v1/calls/create | Start an outbound call — requires calls:create |
GET /api/v1/webhook-endpoints | List webhook endpoints — requires webhooks:read |
POST /api/v1/webhook-endpoints | Register a webhook endpoint — requires webhooks:write |
PATCH /api/v1/webhook-endpoints/{endpoint_id} | Update a webhook endpoint — requires webhooks:write |
DELETE /api/v1/webhook-endpoints/{endpoint_id} | Delete a webhook endpoint — requires webhooks:write |
POST /api/v1/webhook-endpoints/{endpoint_id}/rotate | Rotate a signing secret — requires webhooks:write |
POST /api/v1/webhook-endpoints/{endpoint_id}/test | Send a test webhook — requires webhooks:write |
GET /api/v1/webhook-deliveries | List recent webhook deliveries — requires webhooks:read |
POST /api/v1/webhook-deliveries/{delivery_id}/redeliver | Redeliver a webhook — requires webhooks:write |
POST /api/v1/mcp | Model Context Protocol endpoint (read-only) |
POST /api/v1/application-events | Report an application outcome — requires applications:write |
GET /api/v1/application-events | Application funnel counts — requires applications:write |
Every endpoint that creates something requires an Idempotency-Key header — any unique value you generate per logical request.
Keys are remembered for 24 hours. Field order in your JSON does not matter.
List endpoints return a cursor. Pass it back as cursor to get the next page; when has_more is false you are done. Page size defaults to 25 and caps at 100.
Cursors are stable while records are being added, so you will not see duplicates or skips partway through a sync.
{ "data": [...], "has_more": true, "next_cursor": "eyJ..." }Every error has the same shape. Branch on code, not on the message — codes are stable, wording may improve.
{
"error": {
"code": "scope_missing",
"message": "This API key is missing the `contacts:write` scope.",
"request_id": "req_..."
}
}Minute budgets apply to both the individual key and the whole customer account, so creating more keys does not multiply capacity. Exceeding a limit returns 429 with a Retry-After header.
Register an HTTPS endpoint and we will POST events to it. Endpoint creation requires an Idempotency-Key; the signing secret is returned only in the first successful response. If that response is lost, rotate the secret instead of trying to recover it.
Verify every delivery. The GetsYou-Signature header contains a timestamp and one or more signatures. Recompute and compare before trusting the body.
Sign against the *raw* request body, before any JSON parsing — re-serializing changes the bytes and the signature will not match.
Failed deliveries retry five times over about half a day (1m, 5m, 30m, 2h, 8h). An endpoint that keeps failing is switched off automatically and shows a reason in the dashboard. Each delivery carries a unique GetsYou-Event-Id; treat repeats of the same id as duplicates.
From Settings → Developers you can send a signed test event, inspect delivery history, and manually redeliver a failed event. Manual redelivery creates a new delivery id while preserving the original event type and payload, so it is visible as a separate operator action.
| Event | Fires when |
|---|---|
contact.created | A contact was created |
contact.updated | A contact was updated |
contact.stage_changed | A contact moved to a different pipeline stage |
call.completed | A call finished, with its outcome |
appointment.booked | An appointment was booked |
application_link.sent | The secure application link was texted to a borrower |
application.started | A borrower started their application |
application.submitted | A borrower submitted their application |
documents.requested | Documents were requested from a borrower |
documents.completed | A borrower finished uploading requested documents |
import crypto from "node:crypto";
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(
header.split(",").map((p) => p.trim().split("="))
);
const timestamp = Number(parts.t);
// Reject anything older than 5 minutes — that is the replay window.
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
// A rotating endpoint receives two v1 values; either may match.
return header
.split(",")
.filter((p) => p.trim().startsWith("v1="))
.some((p) => crypto.timingSafeEqual(
Buffer.from(p.trim().slice(3), "hex"),
Buffer.from(expected, "hex"),
));
}Endpoint: https://www.getsyou.ai/api/mcp. A plain GET on that URL returns a short service description with no credentials required. https://www.getsyou.ai/api/v1/mcp is a compatibility alias serving the identical tools; point new integrations at the canonical URL.
Transport is JSON-RPC 2.0 over HTTP POST. Supported methods: initialize, tools/list, tools/call, ping. Tool failures are reported inside the JSON-RPC error member rather than as an HTTP error, which is what MCP clients expect.
Authentication is optional, which is the important part. Send no credentials and you get the public benchmark tools — deliberate, so an assistant with no account can still describe and cite the benchmark accurately. Send Authorization: Bearer <api key> and you additionally get tools scoped to that key's own account, gated by the scopes the key already carries.
Sending no credential is the only route to the public-only tier. A credential that is sent but cannot be used — invalid, revoked, expired, suspended, or on an account without API access — fails the request with a reason rather than quietly falling back to the public tools.
There are no write tools. Every tool is read-only: nothing here can start a call, message a contact, change a record, or spend money.
Before quoting a benchmark value, check the release status. A methodology_preview release publishes definitions and gates but has no measured values to quote.
search_benchmark_releasesno credentialsList GetsYou's public operations-benchmark releases with their status, measurement period, and machine-readable download URLs. Returns published values only when a release has passed every publication gate.
release_id — Optional release id, e.g. rei-operations-v0.1.explain_benchmark_methodologyno credentialsReturn the exact definition of a benchmark metric — formula, numerator, denominator, exclusions, minimum sample — plus the cohort weighting, percentile method, and publication gates. Use this before citing any GetsYou benchmark figure.
metric_id — Optional metric id: live_answer_rate, seller_contact_rate, qualification_yield, or appointment_yield. Omit for all.recommend_workflowno credentialsGiven an operational problem in a real-estate-investor seller pipeline, name the GetsYou agent that addresses it, what it produces, and its stated limits. Returns only agents with published production evidence.
problemrequired — The operational problem, e.g. 'inbound seller calls go to voicemail' or 'follow-up runs hours late'.get_my_benchmark_scorebenchmark:readReturn the authenticated organization's own operations-benchmark rates for the last 30 days, with trend, sample adequacy, and the current funnel bottleneck. Cross-organization comparison is returned only when the cohort privacy gates pass.
get_my_benchmark_auditbenchmark:readReturn how the authenticated organization's benchmark rates were computed: per-metric numerator, denominator, minimum required sample, and whether each metric cleared it.
list_agentsagents:readList the AI agents on this account, with their status, industry, language and phone number.
list_contactscontacts:readList contacts, newest first. Optionally filter by pipeline stage, tag, or a phone number.
stage — Pipeline stage to filter by.tag — Tag to filter by.phone — Phone number to filter by.limit — Maximum contacts to return (default 25, max 100).get_contactcontacts:readRetrieve a single contact by id.
contact_idrequired — The contact's id.list_callscalls:readList calls, newest first. Optionally filter by contact, agent or status.
contact_id — Only calls for this contact.agent_id — Only calls placed by this agent.status — Only calls in this status.limit — Maximum calls to return (default 25, max 100).get_call_outcomecalls:readRetrieve one call's status, duration, outcome and summary. Does not include the transcript.
call_idrequired — The call's id.contacts:write and nothing else.