Skip to main content
Lists store the contact fields Fuse knows about: name, title, company, and so on. Custom columns are where your data goes — a lead score from your model, an account owner, a link to the CRM record. A column is defined once per list with a type, and every contact in the list gets a cell you can write to and read back. All three endpoints on this page require a key with the lists scope.

Column types

Every column has a type, and the type is enforced when you write values. Pick the type that matches the data — it keeps your writes honest and makes the values render correctly in the app.
Enum (picklist) columns exist in the Fuse app but cannot be created through the API yet. If you need a constrained vocabulary today, use a string column and enforce the vocabulary on your side.

Create a column

POST /business/lists/{listId}/columns with a name (max 100 characters) and an optional type. If you omit type, you get a string column.
Hold on to the id — every later write targets the column by id, and row reads key values by it too. Column names must be unique within a list, and the match is case- and whitespace-insensitive: "Lead Score", "lead score", and " Lead Score " all collide. This prevents near-duplicate columns that look distinct but would be indistinguishable to a human scanning the list. A duplicate name returns:
That is a 409 in the standard error envelope. If your integration creates columns idempotently, treat COLUMN_NAME_TAKEN as “already exists” and fetch the existing definition instead.

List a list’s columns

GET /business/lists/{listId}/columns returns every custom column defined on the list:
Use this to build a name → id map when you did not create the columns yourself, or to recover an id after a 409 on create.

Write values

PATCH /business/lists/{listId}/columns/{columnId}/values writes cells in bulk. Each entry pairs a contactId (from the list’s rows) with a value. You can send up to 500 rows per call; batch larger updates across multiple requests.

How values are validated

For string, number, boolean, and date columns, send either the native JSON type or a string — strings are coerced against the column’s type. "42" is accepted by a number column, "true" by a boolean column, "2026-08-01" by a date column. This exists so you can pipe values straight out of a CSV or a spreadsheet without converting types first. url columns are stricter: the value must be an object with both label and value, each non-empty and at most 5,000 characters. A bare URL string is rejected — the label is what renders as the link text in the app, so the API refuses writes that would produce an unlabeled link. To clear a cell, send "" (an empty string) as the value.
A value that fails coercion — say "maybe" sent to a boolean column — rejects the whole request with a 422. Fix or drop the offending row and resend the batch.

Read values back

Column values come back on GET /business/lists/{listId}/rows, in each row’s columnValues object — keyed by column id, not name:
To present values by name, fetch the column definitions once and map ids to names client-side.

Use column values in campaigns

Custom column values are available as merge tokens in campaign templates: {Column: Lead Score} renders each contact’s cell value into the email at send time. This makes columns the bridge between your data pipeline and personalized outreach — write a value per contact, reference it in the template, and every recipient gets their own. See campaigns for how templates and variables work.

Where to next

Export a list

Get the list — and the data you attached to it — out as a CSV.

Campaigns end to end

Reference your columns as merge tokens in outbound sequences.

Upload your contacts

Bring your own contacts, then annotate them with columns.

Errors

The envelope behind COLUMN_NAME_TAKEN and every other failure.