> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs-parschat.parstechai.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs-parschat.parstechai.com/_mcp/server.

# Quickstart

> Create a robot, connect a channel, and receive your first event.

## Before you start

API access comes with a plan. You need **Commercial**, **Professional**, or the **Instagram API**
plan, or an active free trial. See [pricing](https://parstechai.com/products/parschat/).

With one of those active, set up the rest at [chat.parstechai.com](https://chat.parstechai.com):

|                 |                                                                                                                        |
| --------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **API key**     | Create it in the panel, step by step in [Get your API key](/documentation/get-started/authentication#get-your-api-key) |
| **Webhook URL** | Your HTTPS endpoint. You set it in the panel, on the same page as the key                                              |
| **Return URL**  | Give it to your ParsChat contact before your first Instagram connection                                                |

> **Info**
>
> Creating and deleting robots, and connecting an Instagram service, are partner operations. If
> you need them, [contact sales](mailto:info@parstechai.com).

## The one thing to know first

**A service always belongs to a robot.** You cannot connect an Instagram page on its own. Create
the robot, then attach the service to it.

#### Create a robot

A workspace that holds conversations, automation rules and training data.

#### Connect a service to it

For Instagram this starts a browser handshake. The page owner authorises it themselves.

#### Receive events

Every message, state change and reaction arrives on your webhook.

If you manage many end customers, create one robot per customer. That is what keeps one customer's
conversations out of another's.

## 1. Create a robot

**`cURL`**

```bash cURL
curl -X POST https://api-chat.parstechai.com/v1/robots \
  -H "Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Rose Flower Shop",
    "external_id": "shop_10422"
  }'
```

**`Python`**

```python Python
import requests

robot = requests.post(
    "https://api-chat.parstechai.com/v1/robots",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={"name": "Rose Flower Shop", "external_id": "shop_10422"},
    timeout=10,
).json()
```

**`Node.js`**

```javascript Node.js
const res = await fetch("https://api-chat.parstechai.com/v1/robots", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "Rose Flower Shop", external_id: "shop_10422" }),
});
const robot = await res.json();
```

**`Response`**

```json Response
{
  "id": "rbt_8fK2mQ",
  "name": "Rose Flower Shop",
  "external_id": "shop_10422",
  "channels": [],
  "created_at": "2026-09-20T11:04:33Z"
}
```

`external_id` is yours. Put your own customer id in it and we return it on every event, so you
never need a lookup table.

> **Warning**
>
> Each robot consumes one unit of your plan's capacity. When it runs out you get
> `403 capacity_exhausted`. Deleting a robot frees capacity immediately.

## 2. Start the service connection

**`cURL`**

```bash cURL
curl -X POST https://api-chat.parstechai.com/v1/robots/rbt_8fK2mQ/channels \
  -H "Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "type": "instagram" }'
```

**`Python`**

```python Python
channel = requests.post(
    f"https://api-chat.parstechai.com/v1/robots/{robot['id']}/channels",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={"type": "instagram"},
    timeout=10,
).json()
```

**`Node.js`**

```javascript Node.js
const res = await fetch(
  `https://api-chat.parstechai.com/v1/robots/${robot.id}/channels`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ type: "instagram" }),
  },
);
const channel = await res.json();
```

**`Response`**

```json Response
{
  "id": "chn_3pQ7xL",
  "type": "instagram",
  "robot_id": "rbt_8fK2mQ",
  "status": "pending_authorisation",
  "authorisation_url": "https://api-chat.parstechai.com/v1/connect/ig/svc_4dR8nW",
  "expires_at": "2026-09-20T12:04:33Z"
}
```

> **Warning**
>
> **This does not connect anything yet.** Instagram requires the page owner to authorise in their
> own browser. Send them to `authorisation_url`. The channel activates when they finish.
>
> Read [Connect Instagram](/documentation/guides/connect-instagram) before you build this flow. There is a redirect
> back to your panel that has to be configured first.

## 3. Confirm the service is live

```bash
curl https://api-chat.parstechai.com/v1/robots/rbt_8fK2mQ/channels \
  -H "Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxx"
```

**`Response`**

```json Response
{
  "data": [
    {
      "id": "chn_3pQ7xL",
      "type": "instagram",
      "robot_id": "rbt_8fK2mQ",
      "username": "rose.flower.shop",
      "is_active": true,
      "connected_at": "2026-09-20T11:06:10Z"
    }
  ]
}
```

## 4. Verify your first event

Events arrive at the webhook URL you set in your panel. Verify the signature before you trust a
payload.

**`Event`**

```json Event
{
  "schema_version": "1.1.0",
  "event": "message",
  "delivery_id": "dlv_9fK2mQ",
  "occurred_at": "2026-09-20T11:09:02Z",
  "robot_id": "rbt_8fK2mQ",
  "external_id": "shop_10422",
  "channel_id": "chn_3pQ7xL",
  "data": {
    "conversation_id": "cnv_4dR8nW",
    "message_id": "msg_1aB2cD",
    "source": "direct",
    "role": "client",
    "type": "text",
    "text": "Hi, do you have these roses in stock?",
    "attachments": [],
    "sender": {
      "id": "iguser_88213",
      "username": "sara.k",
      "name": "Sara Karimi",
      "avatar_url": "https://api-chat.parstechai.com/v1/files/avatars/gAAAAABpK3xQ8bT2vY0mN4cR7wE1sH9dL6kJ5fG3aZ2qX8uV"
    },
    "created_at": "2026-09-20T11:09:02Z"
  }
}
```

The signature arrives in `X-ParsChat-Signature` as the hex HMAC-SHA256 of the raw request body,
keyed with your secret.

**`Python`**

```python Python
import hashlib
import hmac

def is_authentic(raw_body: bytes, header_signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header_signature)
```

**`Node.js`**

```javascript Node.js
import crypto from "node:crypto";

function isAuthentic(rawBody, headerSignature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(headerSignature),
  );
}
```

**`PHP`**

```php PHP
function is_authentic(string $rawBody, string $headerSignature, string $secret): bool
{
    $expected = hash_hmac('sha256', $rawBody, $secret);
    return hash_equals($expected, $headerSignature);
}
```

> **Warning**
>
> Verify against the raw bytes, before any JSON parsing. Re-serialising the payload changes key
> order and whitespace, and the signature will never match.

Reply `2xx` as soon as you have stored the event. Anything else, including a timeout, is retried.
See [Webhook events](/documentation/guides/webhook-events#retries).

## Common errors

| Status | Meaning                                                      |
| ------ | ------------------------------------------------------------ |
| `401`  | Key is wrong, revoked, or expired                            |
| `403`  | Missing role, plan inactive, or capacity exhausted           |
| `404`  | No such resource, or not yours                               |
| `409`  | Duplicate `external_id`, or service type already present     |
| `422`  | Validation failed                                            |
| `429`  | Rate limited. Back off and retry; `details` names your limit |

Every `code` is listed in [Errors](/documentation/reference/errors).

## Next

#### [Connect Instagram](/documentation/guides/connect-instagram)

The full redirect flow, and the return URL you configure first.

#### [Replying to customers](/documentation/guides/replying-to-customers)

Send text, files and voice notes back to the end customer.

#### [Webhook events](/documentation/guides/webhook-events)

Every event type, full payload contract, retry behaviour.

#### [Instagram automation](/documentation/guides/instagram-automation)

Keyword triggers, public replies, follow gating, targeting one post.

#### [API Reference](/api-reference/robots/create-robot)

Every endpoint, with a live playground.