What you can do with the API
Use the REST API to read submissions and form metadata, post leads from a server-side workflow, or update form names and destination tabs from your own admin tooling. The API exposes the stable lead and form fields integrations need while keeping internal classifier feedback private.
Per-site Bearer auth
Each key is scoped to a single site. Rotate or revoke instantly from Settings → API.
Page-based pagination
Predictable page and per_page query params with a pagination object on every list response.
Granular scopes
Read or write submissions and forms separately. Fail safe with insufficient_scope on mismatch.
OpenAPI 3.1 spec
Drop the spec into Postman, Stoplight, or any code generator and you're live in minutes.
Quick start
In four steps, you'll have a working request against your own site:
- Open Settings → API for the site you want to access.
- Click Create API key, name it, and pick the scopes it needs.
- Copy the key - you'll only see it once - and store it in your secrets manager.
- Make a request:
curl https://app.leadtosheet.com/api/v1/submissions \
-H "Authorization: Bearer lts_your_key_here"Or from Node 18+:
const res = await fetch(
"https://app.leadtosheet.com/api/v1/submissions",
{ headers: { Authorization: "Bearer lts_your_key_here" } }
);
const { data } = await res.json();
console.log(data);Authentication
Every request needs an Authorization: Bearer <key> header. Keys are scoped to a single site - there is no separate site_id to pass.
We store only an HMAC-SHA256 hash of each key, so we can never recover one if you lose it. Revoke and recreate instead.
Scopes
Each key carries one or more scopes. Pick the minimum set for what your integration needs:
| Scope | Grants |
|---|---|
submissions:read | List and read submissions |
submissions:write | Create new submissions (programmatic ingest) |
forms:read | List and read forms |
forms:write | Update form metadata (rename, ignore, change sheet tab) |
Errors
Errors always have the same shape so you can match on error.code in your client:
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"error": {
"code": "insufficient_scope",
"message": "This API key does not have the required scope: submissions:write."
}
}| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated | Missing or malformed Authorization header. |
| 401 | invalid_key | Key not recognized, revoked, or site inactive. |
| 403 | insufficient_scope | Key is valid but missing the required scope. |
| 404 | not_found | Resource doesn't exist on this site. |
| 422 | validation_error | Body or query failed validation. Check error.details. |
| 429 | quota_exceeded | Submission quota is exhausted for the current period. |
| 403 | subscription_inactive | The site account is canceled or incomplete and cannot accept submissions. |
| 403 | trial_expired | The trial has expired and the account must upgrade before collecting submissions. |
Pagination
List endpoints accept page (default 1) and per_page (default 25, max 100). Responses always include a pagination object with page, per_page, total, and total_pages.
{
"data": [ /* … */ ],
"pagination": {
"page": 1,
"per_page": 25,
"total": 142,
"total_pages": 6
}
}Submissions
Anything captured via the SDK or a form endpoint becomes a submission. Read them, filter them, or post your own.
List submissions
/api/v1/submissionsscopesubmissions:readform_id, sync_status (pending / synced / failed), is_spam, from, to (ISO-8601), search (free text across URL, UTM, and field values).curl "https://app.leadtosheet.com/api/v1/submissions?per_page=2&sync_status=synced" \
-H "Authorization: Bearer lts_your_key_here"{
"data": [
{
"id": "sub_01HW6...",
"form_id": "form_01HW5...",
"site_id": "site_01HW4...",
"submitted_at": "2026-05-03T10:14:22.000Z",
"synced_at": "2026-05-03T10:14:23.812Z",
"sync_status": "synced",
"source": "sdk",
"is_spam": false,
"url": "https://acme.com/contact",
"referrer": "https://google.com/",
"fields": {
"email": "jane@example.com",
"message": "Interested in your enterprise plan."
},
"utm": {
"source": "google",
"medium": "cpc",
"campaign": "spring_2026",
"term": null,
"content": null
},
"click_ids": {
"gclid": "EAIaIQobCh...",
"fbclid": null,
"msclkid": null,
"ttclid": null,
"li_fat_id": null
}
}
],
"pagination": { "page": 1, "per_page": 2, "total": 1, "total_pages": 1 }
}Get a submission
/api/v1/submissions/{id}scopesubmissions:readcurl https://app.leadtosheet.com/api/v1/submissions/sub_01HW6abc \
-H "Authorization: Bearer lts_your_key_here"Create a submission
/api/v1/submissionsscopesubmissions:writeSend an existing form_id, or omit it and provide a stable form.key so LeadToSheet can create or reuse an API form for server-side submissions.
curl https://app.leadtosheet.com/api/v1/submissions \
-H "Authorization: Bearer lts_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"form": { "key": "server-contact", "name": "Server Contact" },
"fields": {
"email": "jane@example.com",
"name": "Jane Doe",
"message": "Hello!"
},
"url": "https://acme.com/contact",
"utm": { "source": "newsletter", "medium": "email" },
"click_ids": { "gclid": "EAIaIQobCh..." }
}'HTTP/1.1 201 Created
Content-Type: application/json
{
"id": "sub_01HW6new...",
"form_id": "form_01HW5...",
"site_id": "site_01HW4...",
"submitted_at": "2026-05-03T11:02:14.000Z",
"synced_at": null,
"sync_status": "pending",
"source": "api",
"is_spam": false,
"fields": { "email": "jane@example.com", "name": "Jane Doe", "message": "Hello!" },
"utm": { "source": "newsletter", "medium": "email", "campaign": null, "term": null, "content": null },
"click_ids": { "gclid": "EAIaIQobCh...", "fbclid": null, "msclkid": null, "ttclid": null, "li_fat_id": null }
}HTTP/1.1 200 OK
Content-Type: application/json
{
"duplicate": true,
"message": "An identical submission was received within the dedupe window and was not stored."
}Forms
Forms are detected automatically from the SDK, public API, or first endpoint submission. Use these to inspect or rename them, or to retarget them at a different sheet tab.
List forms
/api/v1/formsscopeforms:readignored filter to include or exclude archived forms.curl https://app.leadtosheet.com/api/v1/forms \
-H "Authorization: Bearer lts_your_key_here"{
"data": [
{
"id": "form_01HW5...",
"site_id": "site_01HW4...",
"scope_key": "site",
"fingerprint": "a1b2c3d4",
"action": "/contact",
"method": "POST",
"name": "Contact form",
"page_name": "Home",
"form_type": "contact",
"field_keys": ["email", "name", "message"],
"sheet_tab_name": "Contact",
"ignored": false,
"last_seen_at": "2026-05-03T10:14:22.000Z"
}
],
"pagination": { "page": 1, "per_page": 25, "total": 1, "total_pages": 1 }
}Update form metadata
/api/v1/forms/{id}scopeforms:writename, sheet_tab_name, or ignored. Other fields are read-only.curl -X PATCH https://app.leadtosheet.com/api/v1/forms/form_01HW5... \
-H "Authorization: Bearer lts_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Renamed form",
"sheet_tab_name": "Inbound leads",
"ignored": false
}'Site
A single endpoint that returns the site identity and current month's usage. Useful for surfacing plan limits in your own admin tooling.
/api/v1/sitescopeany read scopecurl https://app.leadtosheet.com/api/v1/site \
-H "Authorization: Bearer lts_your_key_here"{
"id": "site_01HW4...",
"name": "Acme Marketing Site",
"domain": "acme.com",
"google_sheet_id": "1aBc...",
"google_sheet_url": "https://docs.google.com/spreadsheets/d/1aBc...",
"is_active": true,
"created_at": "2026-04-01T08:00:00.000Z",
"usage": {
"subscription_plan": "GROWTH_MONTHLY",
"subscription_status": "ACTIVE",
"monthly_submission_count": 142,
"current_period_end": "2026-06-01T00:00:00.000Z"
}
}OpenAPI spec
The full machine-readable spec lives at /api/v1/openapi.json (OpenAPI 3.1). Drop it into Postman, Insomnia, Stoplight, or any code generator.
Postman
File → Import → Link, paste the spec URL.
Stoplight Studio
New Project → Import → API URL.
openapi-generator
openapi-generator-cli generate -i <url> -g typescript-fetch
Insomnia
Application → Import → From URL.
Next
Form endpoints
Drop-in HTTP POST URLs for any HTML form - no SDK required.
Read referenceNeed help?
Help Center
Step-by-step guides for setup, syncing, billing, and troubleshooting.
Browse help articles