A REST API over the things the system decides: accounts, decisions, the evidence behind them, campaigns and dossiers. JSON in, JSON out, cursor paginated, authenticated with a bearer token.
The API is read-heavy by design. You can request work — a dossier, a re-qualification — and you can record outcomes. You cannot write an evidence record or set a verdict directly, because a claim that arrived without a source would break the one rule the rest of the system depends on.
Base URL and versioning#
- Base URL
- https://api.arvyn.io/v1
- Transport
- HTTPS only — plain HTTP is refused, not redirected
- Content type
- application/json
- Dates
- ISO 8601, UTC, e.g. 2026-08-14T09:12:44Z
- Versioning
- in the path; additive changes ship without a version bump
These are treated as backwards-compatible and can arrive at any time: new fields on a response, new enum values, new endpoints, and new optional request parameters. Write clients that ignore fields they do not recognise.
Authentication#
A bearer token in the Authorization header. Tokens are created per workspace in Settings → API, are scoped to that workspace, and are shown once at creation.
curl https://api.arvyn.io/v1/accounts \
-H "Authorization: Bearer $ARVYN_API_KEY"| Scope | Grants | Use for |
|---|---|---|
| read | Every GET endpoint | Reporting, dashboards, warehouse sync |
| write | Requesting dossiers and re-qualifications, recording outcomes | Two-way CRM integrations |
| admin | Mailbox, campaign and webhook configuration | Provisioning; avoid in day-to-day integrations |
Errors#
Conventional status codes, with a machine-readable code and a human-readable message. The message is for your logs; branch on the code.
{
"error": {
"code": "evidence_expired",
"message": "Decision DEC-4102 rests on evidence that has since been superseded.",
"status": 409,
"request_id": "req_01J9F2K4Q7",
"docs": "https://arvyn.io/docs/concepts/evidence#expiry"
}
}| Status | Code | Means |
|---|---|---|
| 400 | invalid_request | Malformed body, or a parameter outside its allowed range |
| 401 | unauthenticated | Missing, malformed or revoked token |
| 403 | insufficient_scope | Valid token, wrong scope for this endpoint |
| 404 | not_found | No such record in this workspace — including records that exist in another |
| 409 | conflict | The resource changed underneath you; re-read and retry |
| 422 | unprocessable | Well-formed but not permitted, e.g. requesting a dossier for a D-tier account |
| 429 | rate_limited | See rate limits below |
| 5xx | internal | Retry with backoff; include request_id if you report it |
Always log request_id. It is the only thing that makes a support conversation about a specific failure tractable.
Pagination#
Cursor-based. Offsets are not supported, because the underlying records are re-ranked continuously and page 4 of an offset-paginated qualification list is not a stable thing.
- limitintegeroptional
- Page size, 1–200. Defaults to 50.
- cursorstringoptional
- The
next_cursorfrom the previous response. Omit for the first page. - orderstringoptional
created_atorcontact_by. Defaults tocontact_byon decisions, because that is the order the work should actually be done in.
{
"data": [ /* … */ ],
"next_cursor": "eyJvIjoiMjAyNi0wOC0wN1QwOTowMDowMFoifQ",
"has_more": true
}Stop when has_more is false. Do not stop on an empty data array — a page can be empty and still have more behind it when filtering is applied server-side.
Rate limits#
- Read endpoints
- 600 requests / minute / workspace
- Write endpoints
- 60 requests / minute / workspace
- Dossier requests
- 20 / hour / workspace
- Headers
- X-RateLimit-Limit · X-RateLimit-Remaining · X-RateLimit-Reset
- On 429
- Retry-After, in seconds
Honour Retry-After rather than retrying on a fixed schedule. Repeated retries against a limited endpoint extend the window rather than shortening it.
Idempotency#
Every POST accepts an Idempotency-Key header. Requests with the same key inside 24 hours return the original response instead of doing the work twice.
curl -X POST https://api.arvyn.io/v1/dossiers \
-H "Authorization: Bearer $ARVYN_API_KEY" \
-H "Idempotency-Key: dossier-ACC-19022-2026-08-12" \
-H "Content-Type: application/json" \
-d '{ "account_id": "ACC-19022", "focus": "operations" }'Resources#
Accounts#
A company in the workspace graph, with its current tier, window state and score.
- tierA | B | C | Doptional
- Filter by current tier.
- windowopen | closed | heldoptional
- Filter by window state.
- icp_idstringoptional
- Restrict to accounts qualified under one profile.
- updated_sincedateoptional
- Only accounts whose tier, score or evidence changed after this time. The right filter for an incremental sync.
{
"id": "ACC-19022",
"name": "Northwind Freight",
"domain": "example-northwind.test",
"tier": "B",
"score": 76,
"window": { "state": "open", "opened_at": "2026-06-19", "estimated_close": "2026-10-22" },
"latest_decision": "DEC-4417",
"contact_by": "2026-08-07",
"updated_at": "2026-07-24T06:02:11Z"
}Decisions#
Immutable qualification records. A re-qualification creates a new record that supersedes the old one; nothing is edited in place. See reading a decision record.
The deliberation endpoint returns the full transcript — every turn, its move, and the citation it leaned on. It is the endpoint to use if you want to audit whether the adversarial pass is doing anything in your workspace.
Evidence#
Read-only. Records are created by ingestion, never by clients.
- kindstringoptional
- Signal family: hiring, funding, leadership, expansion, tech_change, commitment, distress.
- strengthstrong | moderate | weakoptional
- Minimum strength to return.
- stateverified | stale | changed | deadoptional
- Verification state. Defaults to excluding dead records.
Campaigns#
POST /v1/outcomes is how a reply that arrived somewhere other than the connected mailbox — in your CRM, on the phone, at a conference — gets into the learning loop.
{
"account_id": "ACC-19022",
"kind": "reply",
"classification": "not_now",
"revisit_at": "2026-10-01",
"source": "crm",
"note": "Told us on a call: budget reopens in Q4."
}Dossiers#
Creation is asynchronous. The POST returns immediately with a pending state; subscribe to dossier.completed rather than polling.
- Formats.
GETreturns structured JSON by default; passAccept: application/pdffor the rendered document. - Citations are inline. Every claim in the JSON body carries its evidence id, so a client can render the sources without a second request.
- Focus and meeting time. Both optional; see requesting one.
Next: webhooks, which is how you find out about any of this without polling.