LeadArc Docsv1

Markdown for agents

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

.md

Authentication

One bearer header, checked on every request against what its owner can do right now.

One header

http
Authorization: Bearer lak_live_k7m2p9qh_9fK2mQ7pL4vX8nT3bY6cZ1sD5fG0jH2k

That is the only scheme. No query parameter, no cookie, no basic auth. No header is 401 missing_authorization. A header that is not Bearer <key> is 401 malformed_key.

Key format

PartValueNotes
lakfixedOne secret-scanner rule matches every key
live or testenvironmenttest keys are rejected in v1
8 characterspublic handleSafe to log
32 charactersthe secretHashed with SHA-256, never stored in the clear

What happens on every request

Checked every time, with no cache, so revoking a key works on the next call:

  1. Parse the token. Wrong shape is 401 malformed_key. A test key is 403 test_keys_unsupported.
  2. Compare the secret hash. No match is 401 invalid_key. "No such key" and "wrong secret" give the same error on purpose.
  3. Revoked is 401 key_revoked. Expired is 401 key_expired.
  4. Re-read the owner. Deactivated is 401 owner_deactivated.
  5. Work out which workspaces the owner can reach now, and keep only those the key was given.
  6. Keep only the scopes the owner's role still allows.
  7. Check the endpoint's scope, then count the request against its rate limit.
The grant is a ceiling, never a floor.

Demote or offboard the owner and their keys lose that reach on the next request. Nothing has to be revoked by hand.

Reaching a workspace

The workspace slug is in the path, and the slug is the workspace id:

http
GET https://api.leadarc.io/v1/workspaces/airpay/leads

An unknown slug and a slug you cannot reach give the same error. It never falls back to every workspace you can see.

Object ids

Every id in a response except the workspace slug is an opaque, signed string:

text
lead_BP2vnPmKyttNP2OlH_mWL78t1o6nBVC6oVbHny

Two parts. The payload is base32 of (clientId, localId). The tag is the first 6 hex characters of HMAC-SHA256(API_ID_SECRET, prefix + payload). decodeId verifies the tag. A tampered id fails the tag and returns 404 not_found, so ids are not enumerable and cannot be correlated across workspaces.

The rule that makes the signature useful: after decoding, the handler asserts decoded.clientId === resolvedWorkspace.id. A mismatch is 404, not 403, so an id from another tenant is indistinguishable from an id that does not exist. Without that assertion the signature is decoration.

Publishing them exposes the upstream provider's id space and lets two workspaces on the shared EmailBison instance correlate against each other. Separately, isCreatorId(id) => id < 0 is the codebase's "skip auth, use the mock store" signal, and 57 route files short-circuit on it, several before their auth check. Opaque ids mean a caller can never hand a negative integer to a shared internal helper.

PrefixObjectLocal id source
usr_memberusers.id
lead_leadresponses_index.eb_lead_id
rep_replyresponses_index.eb_reply_id
msg_messagethread_cache.payload message id
note_notelead_BP2vnPmKyttNP2OlH_mWL78t1o6nBVC6oVbHny
tsk_tasktasks.id
mtg_meetingscheduled_meetings.id
evt_event_typeevent_types.id
evh_event_type_hostevent_type_hosts.id
fld_event_type_form_fieldevent_type_form_fields.id
tpl_templatereply_templates.id
tfd_template_folderreply_template_folders.id
ast_assetclient_assets.id
seq_sequencefollowup_sequences.id
stp_sequence_stepfollowup_sequence_steps.id
enr_enrollmentfollowup_enrollments.id
cmp_campaignEmailBison campaign id
ctg_campaign_tagEmailBison tag id
enrv_enrichment_eventenrichment_events.id
key_api_keyapi_keys.id
whk_webhook_endpointapi_webhook_endpoints.id (v2)
whd_webhook_deliveryapi_webhook_deliveries.id (v2)

A caller must treat ids as opaque strings. No parsing, no arithmetic, no sorting.

Handling a key

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