Skip to main content
The AhaSend Contacts API manages the contacts of your account. This page explains what a contact is, how it relates to lists, and the rules that apply to all contact operations.

Contacts and Lists

A contact is one person in your account, found by email address. Contacts are account-global: one contact has one email address, and one email address belongs to at most one contact in the account. The API trims the email address and changes it to lowercase before it stores it. A new contact is on no list. Campaigns send to lists, so a campaign cannot reach a contact until you add it to a list with the Lists API. Each list membership has its own subscription_status. See Memberships. A contact has two kinds of consent:
  • unsubscribed on the contact is account-wide. When it is true, campaigns do not send to the contact on any list. It does not change the contact’s memberships.
  • subscription_status on a membership applies to one list only.
Contacts and suppressions are separate. Create Contact does not read or change suppressions, and a change to unsubscribed does not add or remove a suppression.

Contact Fields

Name a Contact in the Path

Operations on one contact take {id_or_email} in the path:
  • A value in UUID form is read as the contact ID.
  • Any other value is read as an email address. The API trims it and changes it to lowercase.
Percent-encode an email address exactly once as a path segment. For example, user+tag@example.com becomes user%2Btag%40example.com. The official SDKs encode the value for you, so pass them the email address as it is.

Attributes

You define the attribute keys and their types in the dashboard. A write must use a defined key, and its value must match the type: On create, an attribute value cannot be null. On update, the API merges the attributes object into the stored attributes, and a null value removes that key. Attributes that you read can also hold null, arrays or nested objects. Writes accept only the types above.

Pagination

List Contacts returns contacts newest first. Each page gives pagination.has_more, pagination.next_cursor and pagination.previous_cursor. Send next_cursor as after for the next page, or previous_cursor as before for the previous page. You cannot send after and before together. limit is 1 to 100, and the default is 100.

Scopes

To read the lists of a contact, you need lists:read. See Permission scopes.

Idempotency

Create Contact and Batch Upsert Contacts accept an Idempotency-Key header. See Idempotency.

API Operations