# REST API overview

> What the Funnel One REST API does today, and what is coming: the live lead and motion endpoints, and the planned resources.

The REST API lives at:

```txt
https://app.funnelone.ai/api/v1
```

Every request needs an API key in the `Authorization` header. See
[Authentication](https://dev.funnelone.ai/get-started/authentication/).

## Live today

| Endpoint | Scope | What it does |
|---|---|---|
| `POST /api/v1/leads` | `leads.manage` | Send in a lead. |
| `POST /api/v1/lead` | `leads.manage` | The same endpoint under a second name. |
| `POST /api/v1/motions/{id}/start` | `motions.start` | Start a motion for one company. |

### POST /api/v1/leads

Send a lead from your own form, backend or tool. Funnel One matches it to a
company and a contact where it can.

Body (JSON, up to 256 KB). A lead must include an `email` or a `name`;
everything else is optional.

| Field | Type |
|---|---|
| `email` | string |
| `first_name`, `last_name`, `name` | string |
| `title`, `seniority`, `department`, `phone` | string |
| `linkedin_url` | string |
| `company.domain` (or `company_domain`) | string |
| `company.name` (or `company_name`) | string |
| `utm.source`, `utm.medium`, `utm.campaign` (or `utm_source`, `utm_medium`, `utm_campaign`) | string |

Headers:

- `Idempotency-Key` (optional; the first 128 characters are used). Send the same key again
  and you get `409 duplicate_request` instead of a second lead.

Answers:

- `201` with `lead_id`, `status`, `is_test`, `company_id`, `contact_id` and
  `reconciled`.
- `400 invalid_lead`, `409 duplicate_request`, `403 forbidden_scope`,
  `429 rate_limited`. See [Errors](https://dev.funnelone.ai/rest/errors/).

### POST /api/v1/motions/{id}/start

Start a motion for a company from your own systems. The motion must have an
**API call** trigger in its entry settings.

Headers:

- `Idempotency-Key` (required, 1 to 100 visible ASCII characters).

Body (JSON):

```json
{ "companyId": 1234, "contactIds": [55, 56] }
```

`contactIds` is optional, up to 50.

Answers:

- `202 { "status": "queued", "motionId", "companyId" }`: accepted. Funnel One
  decides the entry shortly after, with the same checks as every other
  trigger.
- `200 { "status": "decided", "outcome", "reasonCode", "reason", … }`: you sent
  a key that was already decided, and this is that same decision.
- `400 invalid_request` or `idempotency_key_required`; `404 motion_not_found`
  or `company_not_found`; `409 api_trigger_missing`, `idempotency_key_reused`
  or `engine_off`.

A motion or company in another workspace answers `404`, the same as one that
does not exist.

### Embed endpoints

The public endpoints under `/api/v1` that Funnel One's own form and booking
embeds call (`/api/v1/forms/…`, `/api/v1/meeting-forms/…`) are used by those
embeds, not called directly. They take the form's public key, not an API key.

## Coming soon

The REST API is growing into a full API with the same permissions as the app.
None of this is live yet:

- **Reads and writes** for companies, contacts, opportunities, segments,
  fields, notes and motion enrollments, as pages of `{ rows, nextCursor, total }`.
  Field names will be the same field keys your CRM mapping uses.
- **One error format** for every endpoint, with a request id and a link to the
  error's page.
- **`RateLimit-*` headers** on every response.
- **`Idempotency-Key`** on every write.
- **An OpenAPI 3.1 document** and an [API reference](https://dev.funnelone.ai/rest/reference/) with a
  "try it" panel, generated from the code that serves the API.
- [Webhooks](https://dev.funnelone.ai/rest/webhooks/) and [SDKs](https://dev.funnelone.ai/rest/sdks/).

The API is versioned by its URL and only grows inside `v1`. See the
[versioning policy](https://dev.funnelone.ai/resources/versioning/).

Source: https://dev.funnelone.ai/rest/
