Contacts

Manage contacts and their attributes, within audiences (`publiq.contacts`).

The contacts resource represents a person inside an audience: create, list, update attributes, bulk-import and remove. Contacts are the foundation for sending broadcasts and for template variables.

Method reference

contacts.create

contacts.create(audienceId, params) → Promise<Contact>

Creates a contact inside an audience, with a required email and optional attributes.

Parameters
ParameterTypeDescription
audienceIdRequiredstringID of the audience to add the contact to (part of the URL).
emailRequiredstringContact email.
firstNameOptionalstringFirst name (max 200 chars).
lastNameOptionalstringLast name (max 200 chars).
attributesOptionalobjectFree-form contact attributes (e.g. { plan: "pro", city: "SP" }).

Returns: The created contact — { object: "contact", id, email, ... }.

const contact = await publiq.contacts.create('aud_123', {
email: 'ana@example.com',
firstName: 'Ana',
lastName: 'Silva',
attributes: { plan: 'pro', city: 'SP' },
});
console.log(contact.id); // "ct_..."
The attributes automatically become template variables ({{ first_name }}, {{ plan }}) without needing to pass them again in emails.send. See Variables.

contacts.list

contacts.list(audienceId, { limit?, after? }) → Promise<ContactList>

Lists the contacts of an audience, cursor-paginated.

Parameters
ParameterTypeDescription
audienceIdRequiredstringID of the audience whose contacts will be listed (part of the URL).
limitOptionalnumberItems per page (default 20, max 100).
afterOptionalstringCursor: id of the last item on the previous page.

Returns: List envelope { object: "list", data: Contact[] }. Use the last item id as after on the next call.

const { data } = await publiq.contacts.list('aud_123', { limit: 50 });
// next page:
const next = await publiq.contacts.list('aud_123', { after: data[data.length - 1].id });
Listing is cursor-paginated: iterate by passing the last item id in after until data comes back empty. See Errors & pagination.

contacts.update

contacts.update(id, params) → Promise<Contact>

Updates the name and/or attributes of an existing contact. attributes does a shallow merge with the current values — omitted keys are preserved.

Parameters
ParameterTypeDescription
idRequiredstringID of the contact to update.
firstNameOptionalstringNew first name.
lastNameOptionalstringNew last name.
attributesOptionalobjectAttributes to merge (shallow merge) with the existing ones (e.g. { plan: "enterprise" }).

Returns: The updated contact.

const contact = await publiq.contacts.update('ct_123', {
attributes: { plan: 'enterprise' },
});
console.log(contact.attributes);
Since attributes does a shallow merge, the new attributes are also immediately available as template variables. See Variables.

contacts.import

contacts.import(audienceId, params) → Promise<ImportResult>

Bulk-imports contacts (up to 1000 per call) into an audience. It is skip-and-continue: invalid or duplicate rows are skipped without failing the whole batch.

Parameters
ParameterTypeDescription
audienceIdRequiredstringID of the audience that will receive the imported contacts (part of the URL).
contactsRequiredArray<{ email, firstName?, lastName?, attributes? }>List of contacts to import (up to 1000 items). Each item requires email; firstName, lastName and attributes are optional.

Returns: Import result with counts — { created, skipped, invalid } (in snake_case in the response).

const result = await publiq.contacts.import('aud_123', {
contacts: [
  { email: 'ana@example.com', firstName: 'Ana' },
  { email: 'bob@example.com', firstName: 'Bob', attributes: { plan: 'pro' } },
],
});
console.log(result.created, result.skipped, result.invalid);
Limit of 1000 contacts per call. The batch never fails entirely: rows with an invalid or already-existing email are skipped — always check skipped/invalid in the return to know what did not go through.

contacts.delete

contacts.delete(id) → Promise<void>

Permanently removes a contact.

Parameters
ParameterTypeDescription
idRequiredstringID of the contact to remove.

Returns: No content (204).

await publiq.contacts.delete('ct_123');

Examples show Node, Python and PHP. In Python methods are snake_case (e.g. cancel_run, from_spec) and take a dict; in PHP they are camelCase and take an associative array. Body keys are always camelCase (templateKey, firstName, scheduledAt) — API responses come back in snake_case.

Contacts — Publiq Docs