# HTTP API for integrations

> How to connect Eggent to your site, CRM, bot or automation — get a token, send a message, pass a file, stream the answer and keep the conversation between calls.

Source: https://eggent.ai/docs/external-api/

The **external API** lets another program give the agent a task: your site's backend, a CRM, n8n or Make, your own bot, a background job. You send a message, Eggent runs it like an ordinary chat and returns the answer.

## Base URL {#base-url}

| Where Eggent runs | Base URL |
| --- | --- |
| Cloud | `https://name.cloud.eggent.ai` |
| Your own server | the address Eggent opens at, for example `https://eggent.example.com` |

## Get a token {#token}

1. Open **Settings → API**.
2. Generate an external API token.
3. Store it in your system as a secret.

The token goes in the `Authorization: Bearer <token>` header. Never put it in code that runs in a browser: with it anyone can give the agent any task. On your own server you can set `EXTERNAL_API_TOKEN` instead of generating one; a token from settings takes precedence.

## Send a message {#message}

```http
POST /api/external/message
Authorization: Bearer <token>
Content-Type: application/json
```

```bash
curl -X POST https://name.cloud.eggent.ai/api/external/message \
  -H "Authorization: Bearer $EGGENT_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "crm:client-42",
    "projectName": "Sales",
    "message": "Write a short follow-up email based on the latest notes"
  }'
```

### Request fields {#request}

| Field | Required | What it is |
| --- | --- | --- |
| `sessionId` | yes | A stable conversation key. One per user, thread, customer or job |
| `message` | yes | The task text, non-empty |
| `projectId` | no | Project id (or an exact name, if unique) |
| `projectName` | no | Exact project name |
| `chatId` | no | An existing chat. Usually not needed |
| `currentPath` | no | A working-folder hint for file tasks |

With no project, the message goes to the orchestrator.

### Response {#response}

```json
{
  "success": true,
  "sessionId": "crm:client-42",
  "reply": "Hi Anna! …",
  "context": {
    "activeProjectId": "sales",
    "activeProjectName": "Sales",
    "activeChatId": "0a2f…",
    "activeChatTitle": "Call with Anna",
    "currentPath": ""
  },
  "chatChanged": false,
  "switchedProject": null,
  "createdProject": null
}
```

If the agent switched or created a project during the run, you see it in `switchedProject` and `createdProject`. `chatChanged` is `true` when the conversation is now in a different chat than before this message — the agent moved it — and `activeChatTitle` names that chat.

## How sessionId works {#session}

For each `sessionId`, Eggent remembers the current project, the current chat and the working folder. Reuse the same `sessionId` and the agent continues the same conversation, with its history. A new `sessionId` is a new conversation.

Good keys: `telegram:<user-id>`, `crm:<client-id>`, `slack:<channel>:<thread>`, `job:daily-report`.

## Streaming the answer {#streaming}

Add `Accept: text/event-stream` and the answer comes as a stream of events (SSE) — handy for showing the text as it is written. Each event is JSON on a `data:` line:

| Event | Meaning |
| --- | --- |
| `{"type":"text","delta":"…"}` | The next piece of the answer |
| `{"type":"tool","name":"…","phase":"start"}` | The agent started or finished (`"end"`) using a tool |
| `{"type":"done","result":{…}}` | Done; `result` is the same JSON as without streaming |
| `{"type":"error","status":500,"payload":{…}}` | An error with the status the plain call would have returned |

If the client disconnects mid-answer, the work is not interrupted: the agent finishes it and the result is saved in the chat.

## Sending a file {#files}

```http
POST /api/external/media-message
Authorization: Bearer <token>
Content-Type: multipart/form-data
```

The same fields as `/message`, plus `file` and `kind` (`document`, `photo`, `audio`, `video`, `voice`, `file`). The file is saved to the chat's attachments and the agent sees it. A voice note (`kind=voice`) is transcribed to text first.

```bash
curl -X POST https://name.cloud.eggent.ai/api/external/media-message \
  -H "Authorization: Bearer $EGGENT_API_TOKEN" \
  -F "sessionId=crm:client-42" \
  -F "message=List every deadline in this contract" \
  -F "kind=document" \
  -F "file=@./contract.pdf"
```

## Errors {#errors}

| Status | Cause | Fix |
| --- | --- | --- |
| `400` | Missing `sessionId` or `message` | Send both as non-empty strings |
| `401` | Missing or invalid token | Check the `Authorization: Bearer …` header |
| `404` | Project or chat not found | Check project ids and names |
| `409` | Ambiguous project name, or a chat from another project | Use `projectId` or drop `chatId` |
| `503` | No token configured | Generate one in **Settings → API** |

## Tips {#tips}

- Call the API only from a server, and only over HTTPS.
- Set a generous timeout: a complex task can take several minutes. Or use streaming.
- One real conversation, one `sessionId`.
- A message that starts with `@` and a project's name hands the task to that project, as in the app: the project works in a chat of its own and its answer is part of the reply. See [Projects](https://eggent.ai/docs/projects.md#ask).
- API answers spend balance just like the chat, and always run in full mode.
