Developers

API documentation

A versioned REST API over the same data the interface uses. Token-authed, scoped per token, and bound to one account.

Last updated August 20, 2026

In one minute

Base URL https://app.getfullarc.com/api/v1. Authenticate with Authorization: Bearer <token>. Call GET /me to confirm which account a token belongs to. Subscribe to changes with webhooks rather than polling.

Getting started

The API is REST over HTTPS, returns JSON, and is versioned in the path. Everything lives under:

https://app.getfullarc.com/api/v1

Create a token in Settings → API tokens, choose its scopes, and copy it — the full value is shown once. Then confirm it points where you think it does:

curl https://app.getfullarc.com/api/v1/me \
  -H "Authorization: Bearer fa_your_token_here"
{
  "success": true,
  "tenantId": "clx...",
  "tenantSlug": "your-company",
  "scopes": ["businesses:read", "leads:write"]
}

Do this first in any integration. A token is bound to exactly one tenant, and pushing records with the wrong one puts your data in someone else's account — /me is how you find out before that happens rather than after.

Authentication and scopes

Send the token as a bearer credential on every request. There are no API keys in query strings — a credential in a URL ends up in server logs, browser history and referrer headers.

Authorization: Bearer fa_your_token_here

Every token carries an explicit set of scopes, and a request outside them gets 403 rather than partial results. Grant the narrowest set that does the job: a token that can only read businesses cannot be turned into one that sends email.

ScopeGrants
businesses:readRead businesses and their contacts
businesses:writeCreate and update businesses
leads:writeCreate leads (contact + deal)
contacts:writeUpsert contacts, tags and custom fields
emails:sendSend transactional email
workflows:triggerEnrol contacts into drip campaigns

Treat a token like a password. If one leaks, delete it in Settings — deletion takes effect immediately, and rotating is always cheaper than working out what was done with it.

Endpoints

Identity

Confirm what a token is before you trust it with anything.

EndpointWhat it doesScope
GET /meReturns the tenant a token belongs to and the scopes it carries.

Businesses

The company records your pipeline hangs off.

EndpointWhat it doesScope
GET /businessesPaginated list. Filter by search text, session, rating, or whether a phone, email or website is present.businesses:read
POST /businessesCreate or merge a business.businesses:write
GET /businesses/{id}Full detail including contacts and enrichment history. Accepts an internal id or a Google Place ID.businesses:read
PATCH /businesses/{id}Update fields on one business.businesses:write

Intake

Getting people and opportunities into the CRM from your own site or app.

EndpointWhat it doesScope
POST /leadsCreates a contact and an early-stage deal, de-duplicating on email and phone.leads:write
POST /contactsUpsert a contact by email or phone, with tags and custom fields. No deal is created.contacts:write

Messaging

Send from your own systems through the same engine the product uses.

EndpointWhat it doesScope
POST /emailsSend one transactional email, with optional attachments. Suppression and unsubscribe handling still apply.emails:send
POST /workflows/{workflowId}/triggerEnrol a contact into an active drip campaign. Trigger data becomes template variables.workflows:trigger

Sessions

Prospecting runs, if you use FullArc to find businesses.

EndpointWhat it doesScope
GET /sessionsSearch sessions, newest first, filterable by status and result count.

Webhooks

Manage your subscriptions programmatically — see the webhooks page for payloads.

EndpointWhat it doesScope
GET /webhooksList subscriptions. Secrets are masked.
POST /webhooksCreate a subscription. The signing secret is returned once and never again.
PATCH /webhooks?id=Update a subscription — change its URL, events, or enabled state.
DELETE /webhooks?id=Delete a subscription.

A worked example

Sending a lead from your own website's contact form:

curl -X POST https://app.getfullarc.com/api/v1/leads \
  -H "Authorization: Bearer fa_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "website contact form",
    "contact": {
      "name": "Dana Whitfield",
      "email": "dana@example.com",
      "phone": "+1 555 0134",
      "companyName": "Whitfield Logistics"
    },
    "message": "Looking for a quote on fleet servicing."
  }'
{
  "success": true,
  "contactId": "clx...",
  "dealId": "clx...",
  "deduped": false
}

deduped: true means the email or phone matched somebody already in the CRM and the lead was attached to them instead of creating a second record. Post the same form twice and you get one contact, not two — so you do not need to build that check yourself.

Errors

Failures return a consistent shape, so you can handle them without parsing prose:

{ "success": false, "error": "Insufficient scope (leads:write)" }
StatusMeansWhat to do
400The request body failed validationRead error — it names the field. Do not retry unchanged.
401Token missing, malformed, or deletedCheck the header. Retrying will not help.
403The token lacks the scope for this endpointAdd the scope in Settings and issue a new token.
404No such record in this tenantOften a tenant mismatch rather than a missing record. Check /me.
429Rate limitedBack off and retry — see below.
5xxOur problemRetry with exponential backoff. Persisting? Tell us.

A 404 from a cross-tenant lookup is deliberate. Distinguishing “does not exist” from “exists but is not yours” would confirm the existence of another account's records to anyone holding a token.

Rate limits

Requests are rate limited per client. Every response carries the current state, so you can pace yourself rather than discovering the ceiling by hitting it:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87

On a 429, back off exponentially rather than retrying immediately. For bulk work, prefer one paginated request over many single-record ones — limit on /businesses goes up to 1000.

OpenAPI document

The machine-readable spec is public and needs no token. Point Swagger UI, Redoc, Postman or a client generator straight at it:

curl https://app.getfullarc.com/api/v1/openapi

It is OpenAPI 3.1, and a test compares its paths against the deployed route files — so if it lists an endpoint, that endpoint exists, and if an endpoint exists, it is listed.

Getting help

Something undocumented, unclear, or behaving differently from this page? Write to support@getfullarc.com with the request you sent and what came back. Discrepancies between this page and the API are treated as defects in whichever one is wrong.