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

# 🔑 REST API

> Programmatic access to Orsay via API key

## Overview

The Orsay REST API allows you to manage sequences and access conversations programmatically from your own server. This is useful for:

* Automating sequence creation from a VPS or cron job
* Integrating Orsay into your existing pipeline (e.g., Instagram → DM sequence)
* Building custom automations without going through the dashboard
* Retrieving conversation data for your CRM or analytics tools

## Authentication

All API requests require a **Bearer token** using your API key.

```bash theme={null}
curl -X GET https://client.api.prod.orsay.ai/api/v1/sequences \
  -H "Authorization: Bearer sk_live_your_api_key_here"
```

### Getting your API key

1. Go to **Settings → API Keys** in the Orsay dashboard
2. Click **Generate API Key**
3. Copy the key immediately — it won't be shown again

<Warning>
  Your API key gives full access to your organization's sequences. Keep it secret and never expose it in client-side code.
</Warning>

## Rate Limiting

The API is rate-limited to **200 requests per hour** per organization.

If you exceed this limit, you'll receive a `429 Too Many Requests` response with a `Retry-After` header indicating how many seconds to wait.

## Base URL

```
https://client.api.prod.orsay.ai/api/v1
```

## Endpoints

### Create a Lead

```bash theme={null}
POST /leads
```

Pushes a lead into a sequence, exactly like the Zapier or Make "Create Lead" action, but with a plain API key. The organization is derived from the key: no OAuth token to refresh, so no connection that can expire mid-scenario.

**Body:**

```json theme={null}
{
  "first_name": "Marie",
  "last_name": "Durand",
  "phone": "+33612345678",
  "email": "marie@example.com",
  "sequence_id": "a1b2c3d4-...",
  "url": "https://example.com/form"
}
```

Only `first_name` and `phone` are required. The phone number must be in international format. If `sequence_id` is omitted, the lead is created without being subscribed to a sequence.

**Example:**

```bash theme={null}
curl -X POST https://client.api.prod.orsay.ai/api/v1/leads \
  -H "Authorization: Bearer sk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"first_name":"Marie","phone":"+33612345678","sequence_id":"a1b2c3d4-..."}'
```

**Response (202):**

```json theme={null}
{ "message": "Lead successfully processed" }
```

<Note>
  The target sequence must use the **Contact subscribed to sequence** trigger. A `402` means the organization has no active subscription.
</Note>

***

### List Agents

```bash theme={null}
GET /agents
```

Returns all AI agents for your organization.

**Response:**

```json theme={null}
[
  {
    "id": "e5f6g7h8-...",
    "name": "Sales Agent",
    "is_published": true
  }
]
```

***

### List Profiles

```bash theme={null}
GET /profiles
```

Returns all connected Instagram and WhatsApp profiles.

**Response:**

```json theme={null}
{
  "instagram": [
    {
      "id": "12345678",
      "username": "mybusiness",
      "status": "CONNECTED"
    }
  ],
  "whatsapp": [
    {
      "id": "abcd-1234-...",
      "name": "My WhatsApp",
      "status": "CONNECTED"
    }
  ]
}
```

***

### List Sequences

```bash theme={null}
GET /sequences
```

Returns all sequences for your organization.

**Response:**

```json theme={null}
[
  {
    "id": "a1b2c3d4-...",
    "name": "Welcome DM",
    "trigger": "INSTAGRAM_MESSAGE",
    "channel": "INSTAGRAM",
    "active": true
  }
]
```

***

### Get Sequence

```bash theme={null}
GET /sequences/{sequence_id}
```

Returns full details of a specific sequence.

**Response:**

```json theme={null}
{
  "id": "a1b2c3d4-...",
  "name": "Welcome DM",
  "trigger": "INSTAGRAM_MESSAGE",
  "channel": "INSTAGRAM",
  "active": true,
  "type": "INBOUND",
  "agent_id": "e5f6g7h8-...",
  "profile_id": "12345",
  "inbound_response_delay": 5,
  "inbound_response_delay_unit": "MINUTES",
  "flow": [
    {
      "delay": 0,
      "delay_unit": "MINUTES",
      "content": "Hello! How can I help you?",
      "template_id": null,
      "action": null
    }
  ]
}
```

***

### Create Sequence

```bash theme={null}
POST /sequences
```

**Request body:**

```json theme={null}
{
  "name": "My New Sequence",
  "trigger": "INSTAGRAM_MESSAGE",
  "inbound_response_delay": 5,
  "inbound_response_delay_unit": "MINUTES",
  "agent_id": "e5f6g7h8-...",
  "profile_id": "12345",
  "active": false,
  "flow": [
    {
      "delay": 0,
      "delay_unit": "MINUTES",
      "followup_delays": [
        { "delay": 30, "delay_unit": "MINUTES" }
      ]
    }
  ]
}
```

**Required fields:**

| Field | Type | Description |
| - | - | - |
| `name` | string | Name of the sequence |
| `trigger` | string | Trigger type (see below) |

**Optional fields:**

| Field | Type | Default | Description |
| - | - | - | - |
| `inbound_response_delay` | int | 5 | Delay before first response |
| `inbound_response_delay_unit` | string | "MINUTES" | SECONDS, MINUTES, or HOURS |
| `agent_id` | string | null | AI agent ID to use |
| `profile_id` | string | null | Instagram or WhatsApp profile ID |
| `active` | bool | false | Whether the sequence is active |
| `flow` | array | \[] | Flow steps definition |
| `filtering_agent` | string | null | Filtering agent ID |
| `should_continue_existing_conversations` | bool | false | Continue existing conversations |
| `keywords` | array | null | Trigger keywords |
| `target_accounts` | array | null | Target accounts for scraping |
| `enable_agent_on_conversation` | bool | true | Enable AI agent on conversations |
| `require_manual_approval` | bool | false | Require manual message approval |

**Response (201):**

```json theme={null}
{
  "id": "new-sequence-uuid"
}
```

***

### Update Sequence

```bash theme={null}
PUT /sequences/{sequence_id}
```

Only include the fields you want to update.

**Request body:**

```json theme={null}
{
  "name": "Updated Name",
  "active": true,
  "inbound_response_delay": 10
}
```

**Response:**

```json theme={null}
{
  "id": "a1b2c3d4-...",
  "status": "updated"
}
```

***

### Delete Sequence

```bash theme={null}
DELETE /sequences/{sequence_id}
```

**Response:**

```json theme={null}
{
  "status": "deleted"
}
```

***

### List Conversations

```bash theme={null}
GET /conversations
```

Returns conversations for your organization with optional filters.

**Query parameters:**

| Parameter | Type | Default | Description |
| - | - | - | - |
| `classification` | string | null | Filter by classification: `positive`, `negative`, `undetermined`, `engaged` |
| `is_active` | boolean | null | Filter by active (`true`) or inactive (`false`) status |
| `since` | string | null | ISO 8601 date — only return conversations updated after this date |
| `page_size` | int | 20 | Number of results per page (max 50) |
| `last_lead_id` | string | null | Cursor for pagination (use `next_cursor` from previous response) |

**Example:**

```bash theme={null}
curl -X GET "https://client.api.prod.orsay.ai/api/v1/conversations?classification=positive&is_active=true&page_size=10" \
  -H "Authorization: Bearer sk_live_your_api_key_here"
```

**Response:**

```json theme={null}
{
  "conversations": [
    {
      "lead_id": "a1b2c3d4-...",
      "channel": "WHATSAPP",
      "classification": "positive",
      "is_active": true,
      "first_name": "John",
      "last_name": "Doe",
      "username": null,
      "phone_number": "+33612345678",
      "latest_message_at": "2025-06-01T14:30:00+00:00",
      "latest_inbound_at": "2025-06-01T14:30:00+00:00",
      "latest_outbound_at": "2025-06-01T14:25:00+00:00"
    }
  ],
  "next_cursor": "a1b2c3d4-..."
}
```

<Note>
  Use `next_cursor` as the `last_lead_id` parameter in subsequent requests to paginate through results. When `next_cursor` is `null`, there are no more results.
</Note>

***

### Get Conversation Messages

```bash theme={null}
GET /conversations/{lead_id}
```

Returns the full message history of a conversation.

**Path parameters:**

| Parameter | Type | Description |
| - | - | - |
| `lead_id` | UUID | The lead ID of the conversation |

**Example:**

```bash theme={null}
curl -X GET "https://client.api.prod.orsay.ai/api/v1/conversations/a1b2c3d4-5678-90ab-cdef-1234567890ab" \
  -H "Authorization: Bearer sk_live_your_api_key_here"
```

**Response:**

```json theme={null}
{
  "lead_id": "a1b2c3d4-...",
  "channel": "WHATSAPP",
  "classification": "positive",
  "is_active": true,
  "lead": {
    "first_name": "John",
    "last_name": "Doe",
    "username": null,
    "phone_number": "+33612345678"
  },
  "messages": [
    {
      "message_id": "msg-uuid-1",
      "content": "Hello! How can I help you?",
      "inbound": false,
      "timestamp": "2025-06-01T14:00:00+00:00",
      "status": "DELIVERED",
      "sent_by": "ai",
      "type": "CUSTOM"
    },
    {
      "message_id": "msg-uuid-2",
      "content": "I'd like to know more about your services",
      "inbound": true,
      "timestamp": "2025-06-01T14:05:00+00:00",
      "status": null,
      "sent_by": null,
      "type": null
    }
  ],
  "total_messages": 2
}
```

## Trigger Types

| Trigger | Channel | Type |
| - | - | - |
| `INSTAGRAM_MESSAGE` | Instagram | Inbound |
| `INSTAGRAM_COMMENT` | Instagram | Outbound |
| `INSTAGRAM_STORY_REPLY` | Instagram | Inbound |
| `WHATSAPP_MESSAGE` | WhatsApp | Inbound |
| `CONTACT_CREATED` | WhatsApp | Outbound |
| `CONTACT_SUBSCRIBED_TO_SEQUENCE` | WhatsApp | Outbound |

## Error Codes

| Code | Description |
| - | - |
| `401` | Invalid or missing API key |
| `404` | Resource not found (sequence or conversation) |
| `429` | Rate limit exceeded (200 req/hour) |
| `400` | Invalid request (bad trigger, missing field, invalid date format, etc.) |

## Example: Full Pipeline

```python theme={null}
import requests
import time

API_KEY = "sk_live_your_key_here"
BASE_URL = "https://client.api.prod.orsay.ai/api/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# 1. List sequences
sequences = requests.get(f"{BASE_URL}/sequences", headers=HEADERS).json()
print(f"Found {len(sequences)} sequences")

# 2. Create a new sequence
new_seq = requests.post(f"{BASE_URL}/sequences", headers=HEADERS, json={
    "name": "Auto DM Pipeline",
    "trigger": "INSTAGRAM_MESSAGE",
    "inbound_response_delay": 2,
    "inbound_response_delay_unit": "MINUTES",
    "agent_id": "your-agent-id",
    "profile_id": "your-instagram-profile-id",
    "active": True,
    "flow": [
        {
            "delay": 0,
            "delay_unit": "MINUTES",
            "followup_delays": [
                {"delay": 30, "delay_unit": "MINUTES"},
                {"delay": 120, "delay_unit": "MINUTES"}
            ]
        }
    ]
}).json()
print(f"Created sequence: {new_seq['id']}")

# 3. Update it later
time.sleep(1)  # Small delay between requests
requests.put(f"{BASE_URL}/sequences/{new_seq['id']}", headers=HEADERS, json={
    "name": "Auto DM Pipeline v2",
    "inbound_response_delay": 5,
})
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.