Overview
The Inbox API uses bracket notation for encoding complex data types (objects and arrays) in query parameters. This guide covers the encoding rules and common patterns.
Objects
Objects are encoded using bracket notation with property names.
Object value:
{
"id": "l44e15irdq4db30i77cgphhx",
"timestamp": "2025-01-15T10:30:00.000Z"
}
Encoded in URL:
?cursorId=l44e15irdq4db30i77cgphhx&cursorTimestamp=2025-01-15T10:30:00.000Z
Cursor example
// Preferred: flat cursor parameters
const { data } = await client.get('/threads', {
params: {
cursorId: 'l44e15irdq4db30i77cgphhx',
cursorTimestamp: '2025-01-15T10:30:00.000Z',
limit: 50
}
});
Use the flat cursorId and cursorTimestamp parameters for pagination. The bracket notation form (cursor[id], cursor[timestamp]) is also supported but deprecated.
Arrays
Arrays can be encoded in three ways. All are supported by the API.
Array value:
["df6jbw4h36qm5d9iu2sgn7kx", "g7ht2kw9xr5m8fp3yjnbqvce"]
Option 1: repeated parameters (simplest)
?accountLinkIds=df6jbw4h36qm5d9iu2sgn7kx&accountLinkIds=g7ht2kw9xr5m8fp3yjnbqvce
Option 2: empty bracket notation
Explicitly denotes an array. Useful when there’s only one value:
?accountLinkIds[]=df6jbw4h36qm5d9iu2sgn7kx&accountLinkIds[]=g7ht2kw9xr5m8fp3yjnbqvce
Option 3: indexed bracket notation
Most explicit. Allows reordering and sparse arrays:
?accountLinkIds[0]=df6jbw4h36qm5d9iu2sgn7kx&accountLinkIds[1]=g7ht2kw9xr5m8fp3yjnbqvce
Thread filters
The GET /threads endpoint supports advanced filtering via the filters parameter using nested bracket notation.
// Threads with ANY of these tags (OR logic)
const { data } = await client.get('/threads', {
params: {
'filters[tags][selectedIds][0]': 't8rvk2m5j0xn4wq7ybftcael',
'filters[tags][selectedIds][1]': 'u9swl3n6k1yo5xr8zcgudbfm'
}
});
// Threads with NO tags
const { data: untagged } = await client.get('/threads', {
params: {
'filters[tags][noTags]': true
}
});
By status
// Threads with prospects in specific statuses
const { data } = await client.get('/threads', {
params: {
'filters[statuses][selectedIds][0]': 's3km7xj9wq5p2bvnhfdteoly',
'filters[statuses][selectedIds][1]': 's4ln8yk0xr6q3cw1behsifup'
}
});
// Threads with no status set
const { data: noStatus } = await client.get('/threads', {
params: {
'filters[statuses][noStatus]': true
}
});
By assignee
// Threads assigned to specific members
const { data } = await client.get('/threads', {
params: {
'filters[assignees][selectedIds][0]': 'r3km7xj9wq5p2bvnhfdteoly'
}
});
// Unassigned threads only
const { data: unassigned } = await client.get('/threads', {
params: {
'filters[assignees][noAssignee]': true
}
});
By campaign
// Threads from specific campaigns
const { data } = await client.get('/threads', {
params: {
'filters[campaigns][selectedIds][0]': 'c5nwp8r2j3ym6at0xbkqhfvg'
}
});
// Threads not from any campaign
const { data: noCampaign } = await client.get('/threads', {
params: {
'filters[campaigns][noCampaign]': true
}
});
Sort order
const { data } = await client.get('/threads', {
params: {
'filters[sortOrder]': 'desc' // or 'asc'
}
});
Combined filters
Multiple filters combine with AND logic:
// Active threads + qualified status + assigned to specific member
const { data } = await client.get('/threads', {
params: {
inbox: 'default',
'accountLinkIds[0]': 'df6jbw4h36qm5d9iu2sgn7kx',
'filters[statuses][selectedIds][0]': 's3km7xj9wq5p2bvnhfdteoly',
'filters[assignees][selectedIds][0]': 'r3km7xj9wq5p2bvnhfdteoly',
limit: 50
}
});
Filter parameter reference
| Filter | Parameter | Description |
|---|
| Tags (include) | filters[tags][selectedIds][N] | Show threads with any of these tag IDs |
| Tags (exclude) | filters[tags][noTags] | Show only untagged threads |
| Statuses (include) | filters[statuses][selectedIds][N] | Show threads with any of these status IDs |
| Statuses (exclude) | filters[statuses][noStatus] | Show only threads with no status |
| Assignees (include) | filters[assignees][selectedIds][N] | Show threads assigned to these member IDs |
| Assignees (exclude) | filters[assignees][noAssignee] | Show only unassigned threads |
| Campaigns (include) | filters[campaigns][selectedIds][N] | Show threads from these campaigns |
| Campaigns (exclude) | filters[campaigns][noCampaign] | Show only non-campaign threads |
| Sort order | filters[sortOrder] | "desc" (newest first, default) or "asc" (oldest first) |
| Inbox view | inbox | "default", "no-reply", "requests", or "archived" |
| Account links | accountLinkIds[N] | Filter by specific account link IDs |
| Page size | limit | 1–100 (default 20) |
URL encoding special characters
Values containing special characters must be URL-encoded:
| Character | Encoded |
|---|
| Space | %20 or + |
+ | %2B |
& | %26 |
= | %3D |
[ | %5B |
] | %5D |
: | %3A |
Most HTTP clients handle this automatically.
Helper function
A utility for encoding filter parameters:
function buildFilterParams(filters: {
tagIds?: string[];
statusIds?: string[];
assigneeIds?: string[];
campaignIds?: string[];
noTags?: boolean;
noStatus?: boolean;
noAssignee?: boolean;
noCampaign?: boolean;
sortOrder?: 'asc' | 'desc';
}): Record<string, string | boolean> {
const params: Record<string, string | boolean> = {};
filters.tagIds?.forEach((id, i) => {
params[`filters[tags][selectedIds][${i}]`] = id;
});
filters.statusIds?.forEach((id, i) => {
params[`filters[statuses][selectedIds][${i}]`] = id;
});
filters.assigneeIds?.forEach((id, i) => {
params[`filters[assignees][selectedIds][${i}]`] = id;
});
filters.campaignIds?.forEach((id, i) => {
params[`filters[campaigns][selectedIds][${i}]`] = id;
});
if (filters.noTags) params['filters[tags][noTags]'] = true;
if (filters.noStatus) params['filters[statuses][noStatus]'] = true;
if (filters.noAssignee) params['filters[assignees][noAssignee]'] = true;
if (filters.noCampaign) params['filters[campaigns][noCampaign]'] = true;
if (filters.sortOrder) params['filters[sortOrder]'] = filters.sortOrder;
return params;
}
// Usage
const { data } = await client.get('/threads', {
params: {
inbox: 'default',
...buildFilterParams({
tagIds: ['t8rvk2m5j0xn4wq7ybftcael'],
noAssignee: true
}),
limit: 50
}
});
Common mistakes
Wrong: Using incorrect filter key structure// These parameter names are WRONG
const { data } = await client.get('/threads', {
params: {
'filter[tagIds][0]': 'tag_abc', // Wrong key
'filter[assignedToMemberIds][0]': 'member_abc', // Wrong key
'filter[noAssignee]': true, // Wrong key
inboxView: 'default', // Wrong param name
accountLinkId: 'acc_abc', // Wrong param name
}
});
Correct:const { data } = await client.get('/threads', {
params: {
'filters[tags][selectedIds][0]': 't8rvk2m5j0xn4wq7ybftcael',
'filters[assignees][selectedIds][0]': 'r3km7xj9wq5p2bvnhfdteoly',
'filters[assignees][noAssignee]': true,
inbox: 'default',
'accountLinkIds[0]': 'df6jbw4h36qm5d9iu2sgn7kx',
}
});