> ## Documentation Index
> Fetch the complete documentation index at: https://docs.autonudge.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# API

> Drive your workspace from your own code, or from an AI assistant

Every Nudge workspace has a REST API. Anything an admin can do in the app, a key can do over HTTPS: read and write contacts, import a book of leads, create and toggle triggers, manage templates, send WhatsApp messages. What it deliberately cannot do is change your configuration, your schema, or the app itself.

The common uses: pushing leads in from a website or another system, syncing contact data with a tool Nudge has no native integration for, and pointing an AI assistant at your workspace so you can ask it to do the boring parts.

## Getting a key

Go to **Settings → API** and click **New key**. Name it after whatever will use it, for example "website" or "Claude".

<Warning>
  The full key is shown once, at creation. Copy it then. Afterwards the table shows only the last four characters, and there is no way to reveal it again. Lost a key? Revoke it and make a new one.
</Warning>

Revoking cuts access immediately. Keys are never deleted, so the record of what existed and when it was last used survives.

## Making a request

The same screen shows your workspace's **base URL**. Every key goes in an `Authorization` header:

```bash theme={null}
curl "$BASE/contacts?limit=20" \
  -H "Authorization: Bearer nk_live_..."
```

A quick connectivity check:

```bash theme={null}
curl "$BASE/me" -H "Authorization: Bearer nk_live_..."
```

Responses are JSON. Errors come back as `{"error": "..."}` with a 400, 401 or 404, and the message says what was actually wrong rather than "bad request".

## What you can call

### Contacts

| Request                        | Does                                                                                                  |
| ------------------------------ | ----------------------------------------------------------------------------------------------------- |
| `GET /contacts`                | List contacts. Supports `limit`, `cursor`, `possibility` and `search`.                                |
| `GET /contacts/:id`            | One contact with all its fields.                                                                      |
| `POST /contacts`               | Create one contact. Deduplicates by phone and email, and fires triggers like a form submission would. |
| `POST /contacts` with an array | Bulk import. Up to 100 per call, deduplicated the same way, but triggers stay quiet.                  |
| `PATCH /contacts/:id`          | Update fields, state or owner.                                                                        |
| `DELETE /contacts/:id`         | Remove a contact and its history.                                                                     |
| `GET /contacts/:id/messages`   | That contact's messages and calls.                                                                    |

The bulk import deliberately does not fire triggers. Importing four thousand old leads should not message four thousand people. When you do want an import enrolled in a trigger, enable that trigger with **Include current matches** afterwards.

### Triggers

| Request                | Does                                                |
| ---------------------- | --------------------------------------------------- |
| `GET /triggers`        | List triggers with their state and channels.        |
| `POST /triggers`       | Create or update a trigger, matched by name.        |
| `PATCH /triggers/:id`  | `{"enabled": true}` or `false`.                     |
| `DELETE /triggers/:id` | Delete a trigger and cancel anything it had queued. |

Because `POST /triggers` matches on name, running the same request twice updates rather than duplicates. That makes it safe to keep your triggers in version control and replay them.

### Templates and messages

`GET`, `POST`, `PATCH` and `DELETE` on `/templates` manage the library. `POST /messages` sends WhatsApp to one contact or up to 500:

```bash theme={null}
curl -X POST "$BASE/messages" \
  -H "Authorization: Bearer nk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"to":"nudge:d5f38225-...","body":"Hi [name], following up on your quote."}'
```

Variables resolve per recipient, exactly like a template send.

<Note>
  API sends join the same paced queue as everything else. A script cannot make your reps' numbers send faster than the safety settings allow, which is the point.
</Note>

## Things worth knowing

* **One key, full access.** There are no per-key permissions yet. Treat a key like an admin password and give each integration its own, so you can revoke one without disturbing the others.
* **Creating contacts is standalone-mode only.** If your workspace syncs with HubSpot, contacts come from HubSpot and creating them through the API is refused. Reading, updating and sending work in both modes. See [Standalone vs HubSpot](/crm/native-mode).
* **WhatsApp only, for now.** Email sending through the API is not built yet.
* **Contact ids** are stable. In HubSpot mode they are the HubSpot contact id; standalone they look like `nudge:` followed by a uuid.

## Watching what happens

**Settings → API** lists the last 100 requests: when, which key, what was called, the status, and the error for anything that failed. It keeps 30 days. When an integration misbehaves, look here first. It usually tells you the answer without needing anyone to reproduce anything.

## Using it with an AI assistant

You do not need a REST key for this. **Settings → API** opens with an **AI connectors** card: click **Connect Claude** or **Connect ChatGPT**, and you get a connector URL and a one-time key to paste into that app's own connector settings. From then on you can work the CRM by asking — "import these leads", "which contacts replied this week and got no follow-up", "turn off the reactivation trigger".

A connector key is not the same thing as a REST key, and the difference matters:

* A **REST key** says *a program may do admin things*. It belongs to the workspace.
* A **connector key** says *this person's assistant acts as them*. It belongs to whoever created it, every action it takes lands in the activity feed under their name, and reversible ones can be undone.

So give each person their own connector rather than sharing one, and revoke it the same way you revoke any key.

### Adding contacts by asking

Paste a list, forward a spreadsheet, or describe someone you just got off the phone with, and the assistant can put them in — up to 100 at a time. Four rules govern it:

* **Nothing gets sent.** New contacts arrive as data. No workflow runs and no message goes out, however the contact is staged. Putting a batch through a workflow is a separate decision: enable the workflow in backfill mode.
* **Running the same list twice is safe.** Contacts are matched on phone number, then on email address, so someone already on file is updated instead of duplicated. A contact with neither is refused and named back to you — there would be no way to recognise them next time.
* **The stage applies to new contacts only.** Someone already on file keeps the stage they have — the assistant will tell you which ones it left alone, and you can ask it to move them.
* **Standalone workspaces only.** If your contacts sync from HubSpot, they are created in HubSpot and arrive here on the next sync.

Ask it to undo and it deletes what it created, as long as nothing has happened to those contacts since — one that has picked up a message, a note or a deal is kept, and the assistant says which.

### Bringing your history in

An assistant can also record what has already happened: calls you had, emails from a thread, WhatsApp exchanges, notes, follow-up tasks and deals. This is how a workspace that has been running somewhere else arrives with its past intact rather than starting empty — and it is how you log a call the moment you put the phone down.

**Nothing is sent.** These are records of things that already occurred, written in a finished state that the sending machinery cannot see, so there is no way for a logged message to go out to anybody.

Two consequences worth knowing:

* **A logged reply behaves like a real one.** It puts the conversation in your Inbox and marks the contact as having replied — which also pauses any chase automation for that contact, exactly as a genuine reply would. That is usually what you want; it is worth knowing before you import a year of history into a workspace with live automations.
* **Messages that went out as one campaign can say so.** Tell the assistant they were a campaign and they are grouped on the Bulk Action tab as a single send, with per-recipient results, instead of scattered across timelines.

Deals follow the pipeline you already have: one open deal per contact, so recording a deal on someone who already has one updates it rather than putting a second on the board, and a stage the board has no column for is reported back rather than silently dropped.
