LeadArc Docsv1

Markdown for agents

This page as plain markdown, ready to paste into an LLM.

.md

Templates and assets

Reply templates, the render step that fills them, folders, and workspace assets.

templates:readread bucketreturns list of template

Reply templates

bash
curl -sS https://api.leadarc.io/v1/workspaces/airpay/templates?limit=25 \
  -H "Authorization: Bearer $LEADARC_API_KEY"

Query parameters. Anything else is 400 unsupported_filter.

cursor folder_id limit order visibility

Errors from this endpoint, on top of the common ones: invalid_cursor, not_found.

json
{
  "object": "list",
  "data": [{
    "object": "template",
    "id": "tpl_RkPo3VxECLfgHxyPBBBi5GTDYNiRwMWrLWUEo_",
    "workspace": "airpay",
    "scope": "workspace",
    "name": "Video sent, follow-up 1",
    "subject": "Re: {{first_name}}, the walkthrough",
    "body": "Hi {{first_name}},\n\nHere is that walkthrough for {{company}}: {{asset:loom}}\n\n{{signature}}",
    "is_html": false,
    "visibility": "workspace",
    "folder_id": "tfd_ow492XVxBkyviOTWP5Taa4TGc-SbTMw48fTGOk",
    "order_index": 1,
    "variables": ["first_name", "company", "asset:loom", "signature"],
    "ai_variables": [{ "name": "PAIN_POINT", "read_website": true }],
    "created_by_id": "usr_zaDRRpdu8EPZSU3i89lvZgKPkVQo4uBFA_KOhm",
    "created_at": "2026-06-14T11:00:00Z"
  }],
  "has_more": false,
  "next_cursor": null
}

Notes.

First, body is the raw template with unresolved {{tokens}}. Never send it as an email. Call /render first. This is the single most likely way an agent damages a client, and the whole reason /render exists.

Second, scope is a new field, and it exists because of a real cross-tenant quirk. visibleWhere in the app returns every template with visibility = "global" from any workspace, with no client_id bound on that branch. So a list under /workspaces/airpay/templates legitimately includes rows whose own client_id is a different workspace. Rather than hide that, the API adds scope: "workspace" when reply_templates.client_id equals the requested workspace, and "global" when the row is shared across all of them. A global template's workspace field is null, so the nested-path invariant is never quietly broken.

variables is derived by scanning the body against the app. Three variables (cal_link, one_pager, quarter) are retired from the insert menus but still resolve, so they can appear here on legacy templates.

ai_variables exposes name and read_website only. reply_templates.ai_vars[].instructions is withheld. It is free-text model instructions, which is internal copy and a prompt-injection surface.

reply_templates.group is withheld. It is a legacy bucketing column superseded by folder_id.

templates:readread bucketreturns template

One template

bash
curl -sS https://api.leadarc.io/v1/workspaces/airpay/templates/tpl_RkPo3VxECLfgHxyPBBBi5GTDYNiRwMWrLWUEo_ \
  -H "Authorization: Bearer $LEADARC_API_KEY"

Errors from this endpoint, on top of the common ones: not_found.

templates:readread bucket

Fill the variables for a lead. Read this before sending anything.

bash
curl -sS https://api.leadarc.io/v1/workspaces/airpay/templates/tpl_RkPo3VxECLfgHxyPBBBi5GTDYNiRwMWrLWUEo_/render \
  -X POST \
  -H "Authorization: Bearer $LEADARC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"lead_id":"lead_BP2vnPmKyttNP2OlH_mWL78t1o6nBVC6oVbHny","resolve_ai_variables":"...","overrides":"..."}'

Body fields. An unknown field is rejected.

lead_id resolve_ai_variables overrides

Errors from this endpoint, on top of the common ones: invalid_request, not_found, unprocessable.

json
{
  "lead_id": "lead_BP2vnPmKyttNP2OlH_mWL78t1o6nBVC6oVbHny",
  "resolve_ai_variables": false,
  "overrides": { "PAIN_POINT": "manual claim reconciliation" }
}

Response:

json
{
  "object": "rendered_template",
  "template_id": "tpl_RkPo3VxECLfgHxyPBBBi5GTDYNiRwMWrLWUEo_",
  "lead_id": "lead_BP2vnPmKyttNP2OlH_mWL78t1o6nBVC6oVbHny",
  "subject": "Re: Mary, the walkthrough",
  "body": "Hi Mary,\n\nHere is that walkthrough for Northgate Care: https://www.loom.com/share/abc123\n\nSara Whitfield\nAirPay",
  "is_html": false,
  "resolved": ["first_name", "company", "asset:loom", "signature"],
  "unresolved": [],
  "ready_to_send": true
}

ready_to_send is false whenever unresolved is non-empty. In v2, POST.../leads/{lead}/reply rejects any body still containing an unresolved {{token}} with 422 unprocessable and names the tokens. That is a mechanical precondition, not a warning.

resolveTemplateBody in the app is called from client components and from /api/ai/fill-template, never from the reply-send route. The send route guards only {{ai:NAME}} via hasUnfilledAiToken, and the comment at template-variables.ts:227-231 explains why that guard cannot catch {{first_name}}: the colon in ai:NAME is not a word character, so the two grammars are deliberately separate. And resolveTemplateBody's own contract is that unknown tokens and empty values stay literal.

resolve_ai_variables: true is rejected in v1 with 403 unprocessable. Resolving an {{ai:NAME}} slot calls Anthropic on our account. /api/ai/fill-template exists internally with a per-user hourly cap counted out of action_log (AI_FILL_HOURLY_CAP, default 30), and exposing it through a key needs its own scope and its own spend cap. Use overrides to fill AI slots from the caller's own model, which is the right shape anyway.

templates:readread bucketreturns list of template_folder

Folders with counts

bash
curl -sS https://api.leadarc.io/v1/workspaces/airpay/template_folders?limit=25 \
  -H "Authorization: Bearer $LEADARC_API_KEY"

Query parameters. Anything else is 400 unsupported_filter.

cursor limit order

Errors from this endpoint, on top of the common ones: invalid_cursor.

assets:readread bucketreturns list of asset

Looms, docs, links, snippets

bash
curl -sS https://api.leadarc.io/v1/workspaces/airpay/assets?limit=25 \
  -H "Authorization: Bearer $LEADARC_API_KEY"

Query parameters. Anything else is 400 unsupported_filter.

cursor kind limit order

Errors from this endpoint, on top of the common ones: invalid_cursor.

json
{
  "object": "asset",
  "id": "ast_fdCtnnliOFHi7Bu9YmN1RhbQBGTym_pixihr4u",
  "workspace": "airpay",
  "kind": "loom",
  "title": "Intake walkthrough (2 min)",
  "url": "https://www.loom.com/share/abc123",
  "body": null,
  "visibility": "workspace",
  "order_index": 0,
  "created_by_id": "usr_zaDRRpdu8EPZSU3i89lvZgKPkVQo4uBFA_KOhm",
  "created_at": "2026-06-14T11:00:00Z"
}

kind is loom, doc, link, or text. url carries the link for the first three; body carries the snippet for text and is null otherwise.

client_assets.visibility has only two values, private and workspace. There is no global, unlike reply_templates.visibility and followup_sequences.visibility, which have three. An agent that learns visibility on templates and sends global to assets gets 422 unprocessable. GET /v1/capabilities calls this out in its notes block.

Rows with visibility: "private" are returned only when the key's owner created them.


Base URL https://api.leadarc.io/v1. Generated from the API source.