Skip to main content

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": "thread_abc123",
  "timestamp": "2025-01-15T10:30:00.000Z"
}
Encoded in URL:
?cursor[id]=thread_abc123&cursor[timestamp]=2025-01-15T10:30:00.000Z

Cursor Example

const cursor = {
  id: 'thread_abc123',
  timestamp: '2025-01-15T10:30:00.000Z'
};

// Using axios - params are encoded automatically
const { data } = await client.get('/threads', {
  params: {
    'cursor[id]': cursor.id,
    'cursor[timestamp]': cursor.timestamp,
    limit: 50
  }
});

Arrays

Arrays can be encoded in three ways. All are supported by the API. Array value:
["tag_abc", "tag_xyz", "tag_123"]

Option 1: Repeated Parameters (Simplest)

?tagIds=tag_abc&tagIds=tag_xyz&tagIds=tag_123

Option 2: Empty Bracket Notation

Explicitly denotes an array. Useful when there’s only one value:
?tagIds[]=tag_abc&tagIds[]=tag_xyz&tagIds[]=tag_123

Option 3: Indexed Bracket Notation

Most explicit. Allows reordering and sparse arrays:
?tagIds[0]=tag_abc&tagIds[1]=tag_xyz&tagIds[2]=tag_123

Filter Example

// Filter threads by multiple tags
const tagIds = ['tag_hot_lead', 'tag_enterprise', 'tag_follow_up'];

const { data } = await client.get('/threads', {
  params: {
    // Using indexed notation
    'filter[tagIds][0]': tagIds[0],
    'filter[tagIds][1]': tagIds[1],
    'filter[tagIds][2]': tagIds[2]
  }
});

Common Filter Parameters

The threads endpoint supports various filter combinations:

By Tags

// Threads with ANY of these tags (OR logic)
const { data } = await client.get('/threads', {
  params: {
    'filter[tagIds][0]': 'tag_hot_lead',
    'filter[tagIds][1]': 'tag_customer'
  }
});

// Threads with NO tags
const { data: untagged } = await client.get('/threads', {
  params: {
    'filter[noTags]': true
  }
});

By Status

// Threads with prospects in specific statuses
const { data } = await client.get('/threads', {
  params: {
    'filter[statusIds][0]': 'status_qualified',
    'filter[statusIds][1]': 'status_interested'
  }
});

// Threads with no status set
const { data: noStatus } = await client.get('/threads', {
  params: {
    'filter[noStatus]': true
  }
});

By Assignee

// Threads assigned to specific members
const { data } = await client.get('/threads', {
  params: {
    'filter[assignedToMemberIds][0]': 'member_abc123',
    'filter[assignedToMemberIds][1]': 'member_xyz789'
  }
});

// Unassigned threads only
const { data: unassigned } = await client.get('/threads', {
  params: {
    'filter[noAssignee]': true
  }
});

Combined Filters

Multiple filters combine with AND logic:
// Active threads + qualified status + assigned to specific member
const { data } = await client.get('/threads', {
  params: {
    inboxView: 'default',
    accountLinkId: 'acc_abc123',
    'filter[statusIds][0]': 'status_qualified',
    'filter[assignedToMemberIds][0]': 'member_xyz',
    limit: 50
  }
});

URL Encoding Special Characters

Values containing special characters must be URL-encoded:
CharacterEncoded
Space%20 or +
+%2B
&%26
=%3D
[%5B
]%5D
:%3A
Most HTTP clients handle this automatically:
// axios handles encoding automatically
const { data } = await client.get('/threads', {
  params: {
    'cursor[timestamp]': '2025-01-15T10:30:00.000Z'  // Colon is encoded
  }
});

Helper Function

A utility for encoding filter parameters:
function buildFilterParams(filters: {
  tagIds?: string[];
  statusIds?: string[];
  assignedToMemberIds?: string[];
  noTags?: boolean;
  noStatus?: boolean;
  noAssignee?: boolean;
}): Record<string, string | boolean> {
  const params: Record<string, string | boolean> = {};

  if (filters.tagIds?.length) {
    filters.tagIds.forEach((id, i) => {
      params[`filter[tagIds][${i}]`] = id;
    });
  }

  if (filters.statusIds?.length) {
    filters.statusIds.forEach((id, i) => {
      params[`filter[statusIds][${i}]`] = id;
    });
  }

  if (filters.assignedToMemberIds?.length) {
    filters.assignedToMemberIds.forEach((id, i) => {
      params[`filter[assignedToMemberIds][${i}]`] = id;
    });
  }

  if (filters.noTags) params['filter[noTags]'] = true;
  if (filters.noStatus) params['filter[noStatus]'] = true;
  if (filters.noAssignee) params['filter[noAssignee]'] = true;

  return params;
}

// Usage
const { data } = await client.get('/threads', {
  params: {
    ...buildFilterParams({
      tagIds: ['tag_hot_lead', 'tag_enterprise'],
      noAssignee: true
    }),
    limit: 50
  }
});

Common Mistakes

Wrong: Passing objects directly without bracket notation
// This won't work
const { data } = await client.get('/threads', {
  params: {
    cursor: { id: 'thread_abc', timestamp: '...' }  // Wrong
  }
});
Correct:
const { data } = await client.get('/threads', {
  params: {
    'cursor[id]': 'thread_abc',
    'cursor[timestamp]': '...'
  }
});