Skip to main content

General

Inbox is a DM management platform with a developer API and a team inbox interface, starting with X (Twitter). The API gives you programmatic access to conversations, prospects, and team workflows.
Common use cases include:
  • Messaging automation — Send DMs programmatically with custom workflows
  • CRM integration — Sync conversations to HubSpot, Salesforce, etc.
  • AI chatbots — Build intelligent auto-reply systems
  • Analytics dashboards — Track engagement and conversion metrics
Currently, X (Twitter) DMs are supported. Instagram and LinkedIn are coming in Q2 2026, with TikTok and WhatsApp planned after that. See Supported platforms for the full roadmap.
All plans support a 7-day free trial. API access is available by default.
Replying to contacts who have already messaged you works on all plans at no extra cost. Sending the first message to a new contact requires the Outbound Messages addon ($199/mo) on a paid plan. Enable it in Settings → Billing or email support@inboxapp.com.

IDs and lookups

Every entity has two IDs:
ID TypeFieldExampleUse For
Inbox IDidl44e15irdq4db30i77cgphhxAll API operations
Platform IDplatformId1876543210987654321Lookups from external data
Always use Inbox IDs for API calls. Use platform IDs for lookups.
// Correct: Inbox ID for operations
await client.get(`/threads/${thread.id}`);

// Correct: Platform ID for lookups
await client.get("/threads/lookup", {
  params: { externalPlatformId: "1876543210987654321" },
});
Use the lookup-by-username endpoint:
const { data: threads } = await client.get("/threads/lookup-by-username", {
  params: { username: "jordanrivera" },
});
Returns a flat array of threads across all account links for that username. The username must be an exact match (case-insensitive the @ prefix).For lookup by platform ID instead, use GET /threads/lookup with externalPlatformId and accountLinkId.
The Inbox API doesn’t provide this. Use the X API to lookup users by username:
curl "https://api.twitter.com/2/users/by/username/johndoe" \
  -H "Authorization: Bearer YOUR_X_BEARER_TOKEN"

Messaging

Yes, using the quick send endpoint:
await client.post("/threads/messages", {
  externalPlatformId: "1876543210987654321",
  accountLinkId: "df6jbw4h36qm5d9iu2sgn7kx",
  content: "Hello!",
});
This creates the thread and prospect automatically.
Rate limits are global per team — all endpoints share the same limits, and all API tokens for a team share the same quota.
WindowLimit
Per minute300 requests
Per hour10,000 requests
Per day100,000 requests
See the Rate Limits guide for details and backoff strategies.
X DMs support up to 10,000 characters.
Media attachments are not currently supported via the API. Only text messages can be sent.
MethodUse When
Quick send (POST /threads/messages)Simple one-off messages, don’t need thread object
Standard send (POST /threads/{id}/messages)Multiple messages, need thread details first
Quick send handles thread creation automatically.

Threads and conversations

ViewDescription
defaultActive conversations needing attention
no-replyProspect sent the last message, awaiting your reply
requestsNew message requests
archivedMarked as done
const { data } = await client.get("/threads", {
  params: { inbox: "default" },
});
Set done: true:
await client.patch(`/threads/${threadId}`, {
  done: true,
});
Yes, but it’s permanent:
await client.delete(`/threads/${threadId}`);
Consider archiving (done: true) instead.
Check authorId against your account link IDs. There is no direction field on messages.
const { data: accountLinks } = await client.get("/account-links");
const accountLinkIds = new Set(accountLinks.map((a) => a.id));

const { data } = await client.get(`/threads/${threadId}/messages`, {
  params: { limit: 1 },
});

const lastMessage = data.messages[0];
if (lastMessage && accountLinkIds.has(lastMessage.authorId)) {
  console.log("Last message was from our account");
} else {
  console.log("Last message was from the prospect");
}

Prospects

Prospects are automatically created when:
  1. They send you a DM
  2. You create a thread with them
  3. You use quick send to message them
You cannot create prospects directly.
Use the context update endpoint:
await client.patch(`/prospects/${prospectId}/context`, {
  notes: "Interested in Enterprise plan",
  valuation: 50000,
});
No. Profile data (followers, bio, etc.) is synced periodically. Check isFresh, isStale, and confidence to assess data quality.
Yes. Tags are multi-select. Statuses are single-select. Tags are updated incrementally:
await client.patch(`/prospects/${prospectId}/context`, {
  addTags: ["t8rvk2m5j0xn4wq7ybftcael", "u9swl3n6k1yo5xr8zcgudbfm"],
  statusId: "s3km7xj9wq5p2bvnhfdteoly",
});
There is no tagIds field — use addTags and removeTags to modify tags.

Account connections are managed through the Inbox dashboard:
  1. Go to inboxapp.com
  2. Navigate to Settings → Accounts
  3. Make sure you have the Chrome extension installed
  4. Click Open X and select the account to link
The API is read-only for account links.
Yes. Specify the accountLinkId when sending:
await client.post("/threads/messages", {
  externalPlatformId: "1876543210987654321",
  accountLinkId: "df6jbw4h36qm5d9iu2sgn7kx",
  content: "Hello from sales!",
});
Rate limits are per team — all API tokens for the same team share the same quota. The limits are 300 requests per minute, 10,000 per hour, and 100,000 per day across all endpoints.

Team and members

await client.patch(`/threads/${threadId}`, {
  assigneeId: 'r3km7xj9wq5p2bvnhfdteoly'
});
No. Team member management is done through the Inbox dashboard.
const { data } = await client.get('/threads', {
  params: {
    'filters[assignees][noAssignee]': true
  }
});

Technical

https://inboxapp.com/api/v1
Use cursor-based pagination with cursorId and cursorTimestamp. Only GET /threads and GET /threads/{id}/messages are paginated — other list endpoints return all results as a flat array.
let cursorId: string | undefined;
let cursorTimestamp: string | undefined;

do {
  const { data } = await client.get("/threads", {
    params: {
      limit: 100,
      ...(cursorId && { cursorId, cursorTimestamp }),
    },
  });

  // Process data.threads
  cursorId = data.nextCursor?.id;
  cursorTimestamp = data.nextCursor?.timestamp;
} while (cursorId);
See the Pagination guide.
Use the filters parameter with bracket notation:
const { data } = await client.get("/threads", {
  params: {
    inbox: "default",
    "filters[tags][selectedIds][0]": "t8rvk2m5j0xn4wq7ybftcael",
    "filters[assignees][noAssignee]": true,
  },
});
See the Query Parameters guide for a full reference of filter keys.
Webhooks are not currently available. Use polling to check for new messages.
Not yet. Use any HTTP client (axios, fetch) with the REST API.

Still have questions?