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

# Core concepts

> The resources of the Inboxapp API and how they relate

## Base URL

```txt theme={null}
https://inboxapp.com/api/v2
```

The Inboxapp API gives you access to your team's conversations and the CRM state around them. Every platform uses the same resources, so your code asks what an account can do instead of which platform it is on.

## The data model

```txt theme={null}
Team
├── Members                people on your team
├── Account links          your accounts on each platform
│   └── Threads            one conversation with one profile
│       └── Messages
├── Contacts               your record of a person
│   └── Profiles           their account on each platform
├── Tags                   labels on contacts
└── Statuses               pipeline stages of contacts
```

| Resource | What it is |
| - | - |
| **Platform** | A messaging platform available to your team, with what it supports |
| **Account link** | One of your accounts on a platform. Messages are sent from one |
| **Profile** | One person's account on one platform |
| **Contact** | Your team's record of a person. Groups one or more of their profiles |
| **Thread** | A conversation between one account link and one profile |
| **Message** | A message in a thread, which you can send, edit, unsend and react to |
| **Tag** | A label on a contact. A contact can have several |
| **Status** | A pipeline stage. A contact has at most one |
| **Member** | A person on your team, who can be assigned threads and contacts |

## Authentication

Send your API token in the `Authorization` header: `Authorization: Bearer <token>`. The token decides the team, so no path or parameter names one.

## Profiles and contacts

A **profile** holds what the platform says about a person: `username`, `displayName`, `bio`, follower counts. A **contact** holds what your team says about them: `statusId`, `tagIds`, `notes`, `valuation`, `assigneeId`. A contact groups one or more profiles.

A thread is always with one profile, and its `contactId` points to the contact that profile belongs to.

```json theme={null}
{
  "id": "nq2r8v5ycx1t7m4hj6kd3wzb",
  "profiles": [
    {
      "id": "n7kxqm5d9iu2sgdf6jbw4h36",
      "platform": "twitter",
      "platformId": "1876543210987654321",
      "username": "sarahchen",
      "handle": "@sarahchen",
      "displayName": "Sarah Chen"
    }
  ],
  "statusId": "r3km7xj9wq5p2bvnhfdteoly",
  "tagIds": ["t9wq5p2bvnhfdteolyr3km7x"],
  "notes": "Asked for a demo of the reporting API.",
  "valuation": 12000,
  "assigneeId": null
}
```

Reads never create a contact. Someone your team has never talked to or imported has none: message them by sending to a `profile` target.

## IDs

| Field | What it is | Use it for |
| - | - | - |
| `id`, every `…Id` | An Inboxapp ID | Paths and references. Paths only take Inboxapp IDs |
| `platformId` | The ID the platform gives the object: its user, conversation or message | Matching against your own data |

A `platformId` always comes with a `platform`, and means nothing without it. To find a resource by its platform identity, filter its collection:

```txt theme={null}
GET /contacts?platform=twitter&platformId=1876543210987654321
```

No match is an empty `data` array, never a `404`.

## Platforms and capabilities

Platforms differ: one lets you edit a message, another doesn't. The API expresses that as **capabilities** instead of per-platform endpoints. `GET /platforms` lists the platforms available to your team, with their capabilities and limits.

```txt theme={null}
Platform capabilities              the most any account on the platform can do
  └── Account link capabilities    narrowed for this account
        └── Thread restrictions    disabled in this conversation
```

Check both before you call:

```typescript theme={null}
function canEdit(accountLink: AccountLink, thread: Thread): boolean {
  return (
    accountLink.capabilities.includes("message:edit") &&
    !thread.restrictions.includes("message:edit")
  );
}
```

| Failure | Meaning |
| - | - |
| `422 capabilityNotSupported` | The account link can't do this |
| `422 threadRestricted` | The platform disabled it in this conversation |
| `422 mutationWindowClosed` | The platform's time window for it has passed |
| `403 platformNotAvailable` | The resource is on a platform your team can't use |

New platforms may be added within v2, so treat `platform` as an open string. Code that checks capabilities keeps working when they are. See [Platforms and capabilities](/v2/platforms) for what each platform supports.

## Platform data

Fields every platform has are top-level. Fields only one platform has are in `platformData`, tagged by `_tag`:

```json theme={null}
{
  "platformData": { "_tag": "twitter", "encrypted": true }
}
```

Ignore tags you don't know.

## Responses

Every documented field is present: a value that doesn't apply is `null`. Timestamps are ISO 8601 in UTC. Within v2, fields, enum values and error codes may be added, so ignore unknown fields and handle unknown enum values.

## Pagination

Collections return `{ "data": [...], "nextCursor": "..." }`. Pass `nextCursor` back as `cursor`, with the same filters, to read the next page. It is `null` on the last page. `limit` defaults to 50, up to 100. See [Pagination](/v2/reference/pagination).

## Query parameters

To pass several values, repeat the key:

```txt theme={null}
?accountLinkId=a&accountLinkId=b
```

Brackets (`ids[]=…`) and comma-separated values aren't accepted. See [Query parameters](/v2/reference/query-parameters).

## Expansion

References are IDs by default. Use `expand` to embed the related resource next to its ID field, `contact` beside `contactId`, at most 4 per request:

```txt theme={null}
GET /threads?expand=contact&expand=profile
```

## Updates

In `PATCH` bodies, omitted fields are left unchanged, and `null` clears a nullable field.

## Errors

Every error has the same body:

```json theme={null}
{
  "code": "capabilityNotSupported",
  "message": "This account can't perform this operation.",
  "details": { "capability": "message:edit" },
  "requestId": "…"
}
```

Branch on `code`, the contract. `message` can be shown to a person and may change. `details` is `null` or the object documented for that code. Share `requestId`, also in the `X-Request-Id` header, when you contact support. See [Error codes](/v2/reference/errors).

## Sending safely

`POST /messages` takes an optional `Idempotency-Key` header. Retrying with the same key never sends twice: a replay returns the original result. Without a key, a retry can send twice.

## Rate limits

Each team can make 300 requests per minute, 10,000 per hour and 100,000 per day. Every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. Past a limit, requests fail with `429 rateLimited` and a `Retry-After` header. See [Rate limits](/v2/reference/rate-limits).


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