Genaya

Developers
helpHelp Center
Marketing

Profiles

The marketing contact as a whole person - consent per channel, location, properties and an activity log. Not the call center phone book (Contacts).

GET/profiles

List or look up profiles

A profile is the marketing contact as a whole person: consent per channel, location, how they found you, custom properties and an activity log. It is the person an audience holds - **not** `/v1/contacts`, which is the call center phone book. With no filter this returns a cursor-paginated list of the organization's profiles. With `email` or `phone` it is a lookup: the one person, or an empty list, in the same list envelope (the two filters are not combined with `from` / `to`). A phone must be a US number in any written form (400 `invalid_phone` otherwise). Requires scope: audiences:read.

Parameters

Query

limit
integer
Maximum number of items to return (default 25, max 100).
starting_after
string
A cursor - the id of the last item from the previous page. Returns the items after it.
from
string
Filter to resources created on or after this date. Accepts an ISO-8601 date (2026-06-01, snapped to the start of the UTC day) or a full timestamp (2026-06-01T00:00:00Z). When set, results are ordered newest-first by created date.
to
string
Filter to resources created on or before this date. Accepts an ISO-8601 date (2026-06-30, snapped to the end of the UTC day) or a full timestamp (2026-06-30T23:59:59Z). When set, results are ordered newest-first by created date.
email
string
Look up the profile with this email address (case-insensitive).
phone
string
Look up the profile with this US phone number.

Response 200

FieldTypeDescription
idrequired
string
Unique identifier for the profile.
objectrequired
string
The object type. Always "profile".
email
string
Lowercased email address. Absent for a phone-only profile.
phone
string
US phone number in E.164. Absent for an email-only profile.
firstNamerequired
string
lastNamerequired
string
company
string
Absent when unset.
title
string
Job title. Absent when unset.
statusrequired
string
The email state - "subscribed", "unsubscribed", "bounced" or "complained".
consentrequired
object
Consent per channel. `status` is "subscribed", "unsubscribed" or "never_subscribed" (email can also be "bounced" or "complained"). `at` and `source` appear once a change was recorded.
email
object
sms
object
location
object
Where the person is. Any of city, region, country, timezone.
attribution
object
How they found you. `first` is set once, `last` moves on every touch. Each holds any of source, medium, campaign, content, term, referrer, firstPage.
first
object
last
object
propertiesrequired
object
Your own fields on the person - plain text, numbers and booleans, up to 200 keys.
audienceIdsrequired
array of string
The audiences the person is in.
createdAt
string <date-time>
nullable
updatedAt
string <date-time>
nullable

Errors

400Malformed or missing parameters
401Bad, missing, or revoked key
402The prepaid balance has nothing left for API requests past the included pool, or the trial requests are used up
403Lacks scope, plan without API access, live key on a trial, test key writing, or feature switched off
429Rate limited
500Unexpected server error
POST/profiles

Create or update a profile

Pushes one person: found by email, else phone, and created when new or updated when they exist, so the same person pushed twice is one profile. The response is **201** with `created: true` for a new person and **200** with `created: false` for an existing one. Send an `email`, a `phone` or both (400 otherwise). Fields you omit are left as they are, `properties` merge key by key, and a person who first arrived by phone is carried over when their email turns up. `consent` records an opt-in or opt-out per channel; an opt-out also lands on the suppression lists campaigns read. **An unsubscribed person stays unsubscribed.** A write through this API never re-subscribes anyone: sending `consent.email: "subscribed"` for someone who has unsubscribed, bounced or marked a message as spam is ignored, and the person stays out of every send. Supports idempotent retries via the Idempotency-Key header. Requires scope: audiences:write.

Parameters

Headers

Idempotency-Key
string
Send a unique string to safely retry a create. The first response is replayed for 24h; reusing the key with a different body returns 409.

Request body

FieldTypeDescription
email
string
Email address. Cannot change on an existing profile.
phone
string
A US phone number in any written form, stored as E.164.
firstName
string
Max 80 characters. An empty string clears it on update.
lastName
string
Max 80 characters. An empty string clears it on update.
company
string
Max 120 characters. An empty string clears it on update.
title
string
Max 120 characters. An empty string clears it on update.
consent
object
Record consent per channel (email, sms) as "subscribed", "unsubscribed" or "never_subscribed". An unsubscribe is final through the API: a later "subscribed" for the same person is ignored. To carry a consent over from another system, send an object instead: { "status": "subscribed", "at": "2026-09-30T14:00:00Z", "method": "Klaviyo" }. `at` keeps the date the person agreed, which is your proof, and `method` says where it came from.
email
string
sms
string
location
object
Any of city, region, country, timezone.
attribution
object
`first` and `last`, each any of source, medium, campaign, content, term, referrer, firstPage.
first
object
last
object
properties
object
Your own fields. Keys merge one by one; a value of null removes that key. Values are text (500 characters), numbers or booleans; objects are ignored. Up to 200 keys on a profile.

Response 200

No fields.

Errors

400Malformed or missing parameters
401Bad, missing, or revoked key
402The prepaid balance has nothing left for API requests past the included pool, or the trial requests are used up
403Lacks scope, plan without API access, live key on a trial, test key writing, or feature switched off
409Idempotency-Key reused with a different body
429Rate limited
500Unexpected server error
POST/profiles/bulk

Create or update many profiles

Up to 100 people in one call, each row the same body as POST /profiles. Send `audienceId` to also put them on that list. One bad row never stops the rest: `results` answers row by row. Each row counts as one request and one write. A bulk add starts no flow; a person pushed on their own does. Someone who unsubscribed stays unsubscribed and is not added to the list. Supports idempotent retries via the Idempotency-Key header. Requires scope: audiences:write.

Parameters

Headers

Idempotency-Key
string
Send a unique string to safely retry a create. The first response is replayed for 24h; reusing the key with a different body returns 409.

Request body

FieldTypeDescription
profilesrequired
array of object
email
string
Email address. Cannot change on an existing profile.
phone
string
A US phone number in any written form, stored as E.164.
firstName
string
Max 80 characters. An empty string clears it on update.
lastName
string
Max 80 characters. An empty string clears it on update.
company
string
Max 120 characters. An empty string clears it on update.
title
string
Max 120 characters. An empty string clears it on update.
consent
object
Record consent per channel (email, sms) as "subscribed", "unsubscribed" or "never_subscribed". An unsubscribe is final through the API: a later "subscribed" for the same person is ignored. To carry a consent over from another system, send an object instead: { "status": "subscribed", "at": "2026-09-30T14:00:00Z", "method": "Klaviyo" }. `at` keeps the date the person agreed, which is your proof, and `method` says where it came from.
location
object
Any of city, region, country, timezone.
attribution
object
`first` and `last`, each any of source, medium, campaign, content, term, referrer, firstPage.
properties
object
Your own fields. Keys merge one by one; a value of null removes that key. Values are text (500 characters), numbers or booleans; objects are ignored. Up to 200 keys on a profile.
audienceId
string
A list to add these people to. A segment fills itself, so it is refused.

Response 200

FieldTypeDescription
object
string
created
integer
updated
integer
failed
integer
addedToAudience
integer
results
array of object
index
integer
The row's place in `profiles`, from 0.
id
string
created
boolean
addedToAudience
boolean
error
object

Errors

400Malformed or missing parameters
401Bad, missing, or revoked key
403Lacks scope, plan without API access, live key on a trial, test key writing, or feature switched off
404No such resource in this organization
429Rate limited
GET/profiles/{profileId}

Retrieve a profile

Returns one profile. Returns 404 if it is missing, deleted or belongs to another organization. Requires scope: audiences:read.

Parameters

Path

profileIdrequired
string
The id of the profile.

Response 200

FieldTypeDescription
idrequired
string
Unique identifier for the profile.
objectrequired
string
The object type. Always "profile".
email
string
Lowercased email address. Absent for a phone-only profile.
phone
string
US phone number in E.164. Absent for an email-only profile.
firstNamerequired
string
lastNamerequired
string
company
string
Absent when unset.
title
string
Job title. Absent when unset.
statusrequired
string
The email state - "subscribed", "unsubscribed", "bounced" or "complained".
consentrequired
object
Consent per channel. `status` is "subscribed", "unsubscribed" or "never_subscribed" (email can also be "bounced" or "complained"). `at` and `source` appear once a change was recorded.
email
object
sms
object
location
object
Where the person is. Any of city, region, country, timezone.
attribution
object
How they found you. `first` is set once, `last` moves on every touch. Each holds any of source, medium, campaign, content, term, referrer, firstPage.
first
object
last
object
propertiesrequired
object
Your own fields on the person - plain text, numbers and booleans, up to 200 keys.
audienceIdsrequired
array of string
The audiences the person is in.
createdAt
string <date-time>
nullable
updatedAt
string <date-time>
nullable

Errors

401Bad, missing, or revoked key
402The prepaid balance has nothing left for API requests past the included pool, or the trial requests are used up
403Lacks scope, plan without API access, live key on a trial, test key writing, or feature switched off
404No such resource in this organization
429Rate limited
500Unexpected server error
PATCH/profiles/{profileId}

Update a profile

Send only what changes. An empty string clears a name, company or title, and `properties: { "key": null }` removes a property. A profile's email cannot change (400 `email_locked`): delete it and create a new one. Setting `consent` to unsubscribed also writes the suppression lists, whichever address the request names. **An unsubscribed person stays unsubscribed.** A write through this API never re-subscribes anyone: sending `consent.email: "subscribed"` for someone who has unsubscribed, bounced or marked a message as spam is ignored, and the person stays out of every send. Requires scope: audiences:write.

Parameters

Path

profileIdrequired
string
The id of the profile.

Request body

FieldTypeDescription
email
string
Email address. Cannot change on an existing profile.
phone
string
A US phone number in any written form, stored as E.164.
firstName
string
Max 80 characters. An empty string clears it on update.
lastName
string
Max 80 characters. An empty string clears it on update.
company
string
Max 120 characters. An empty string clears it on update.
title
string
Max 120 characters. An empty string clears it on update.
consent
object
Record consent per channel (email, sms) as "subscribed", "unsubscribed" or "never_subscribed". An unsubscribe is final through the API: a later "subscribed" for the same person is ignored. To carry a consent over from another system, send an object instead: { "status": "subscribed", "at": "2026-09-30T14:00:00Z", "method": "Klaviyo" }. `at` keeps the date the person agreed, which is your proof, and `method` says where it came from.
email
string
sms
string
location
object
Any of city, region, country, timezone.
attribution
object
`first` and `last`, each any of source, medium, campaign, content, term, referrer, firstPage.
first
object
last
object
properties
object
Your own fields. Keys merge one by one; a value of null removes that key. Values are text (500 characters), numbers or booleans; objects are ignored. Up to 200 keys on a profile.

Response 200

FieldTypeDescription
idrequired
string
Unique identifier for the profile.
objectrequired
string
The object type. Always "profile".
email
string
Lowercased email address. Absent for a phone-only profile.
phone
string
US phone number in E.164. Absent for an email-only profile.
firstNamerequired
string
lastNamerequired
string
company
string
Absent when unset.
title
string
Job title. Absent when unset.
statusrequired
string
The email state - "subscribed", "unsubscribed", "bounced" or "complained".
consentrequired
object
Consent per channel. `status` is "subscribed", "unsubscribed" or "never_subscribed" (email can also be "bounced" or "complained"). `at` and `source` appear once a change was recorded.
email
object
sms
object
location
object
Where the person is. Any of city, region, country, timezone.
attribution
object
How they found you. `first` is set once, `last` moves on every touch. Each holds any of source, medium, campaign, content, term, referrer, firstPage.
first
object
last
object
propertiesrequired
object
Your own fields on the person - plain text, numbers and booleans, up to 200 keys.
audienceIdsrequired
array of string
The audiences the person is in.
createdAt
string <date-time>
nullable
updatedAt
string <date-time>
nullable

Errors

400Malformed or missing parameters
401Bad, missing, or revoked key
402The prepaid balance has nothing left for API requests past the included pool, or the trial requests are used up
403Lacks scope, plan without API access, live key on a trial, test key writing, or feature switched off
404No such resource in this organization
429Rate limited
500Unexpected server error
DELETE/profiles/{profileId}

Delete a profile

Takes the person out of the contact list. Saved audiences keep their own recipients and an unsubscribe stays on record, so deleting someone never restarts mail they stopped. Requires scope: audiences:write.

Parameters

Path

profileIdrequired
string
The id of the profile.

Response 200

FieldTypeDescription
objectrequired
string
idrequired
string
deletedrequired
boolean

Errors

401Bad, missing, or revoked key
402The prepaid balance has nothing left for API requests past the included pool, or the trial requests are used up
403Lacks scope, plan without API access, live key on a trial, test key writing, or feature switched off
404No such resource in this organization
429Rate limited
500Unexpected server error
GET/profiles/{profileId}/events

List a profile's activity

The profile's activity log, newest first: sends, opens, clicks, consent changes, list changes, and the named events you recorded. Unlike the other lists, `limit` defaults to 50 and goes up to 100. Filter with `type`, a comma list of event types (profile_created, profile_updated, added_to_audience, removed_from_audience, email_sent, email_delivered, email_opened, email_clicked, email_bounced, email_complained, sms_sent, sms_replied, flow_entered, flow_finished, unsubscribed, consent_changed, event). Requires scope: audiences:read.

Parameters

Path

profileIdrequired
string
The id of the profile.

Query

limit
integer
Maximum number of items to return (default 25, max 100).
starting_after
string
A cursor - the id of the last item from the previous page. Returns the items after it.
type
string
A comma list of event types to return.

Response 200

FieldTypeDescription
idrequired
string
The event id. Use it as the `starting_after` cursor.
objectrequired
string
The object type. Always "profile_event".
typerequired
string
The event type, for example email_opened, consent_changed or event (a named event you recorded).
name
string
The name of an `event`.
atrequired
string <date-time>
When it happened.
channel
string
subject
string
campaignId
string
campaignName
string
flowId
string
flowName
string
audienceId
string
audienceName
string
source
string
detail
string
url
string
properties
object

Errors

401Bad, missing, or revoked key
402The prepaid balance has nothing left for API requests past the included pool, or the trial requests are used up
403Lacks scope, plan without API access, live key on a trial, test key writing, or feature switched off
404No such resource in this organization
429Rate limited
500Unexpected server error
POST/profiles/{profileId}/events

Record an event

Records a named event on the profile - something that happened in your own product, such as "Placed Order". It lands on the activity log and starts any live flow that listens for that name; `enrolledInFlows` says how many. `properties` keep plain text, numbers and booleans; nested objects are dropped. Supports idempotent retries via the Idempotency-Key header. Requires scope: audiences:write.

Parameters

Path

profileIdrequired
string
The id of the profile.

Headers

Idempotency-Key
string
Send a unique string to safely retry a create. The first response is replayed for 24h; reusing the key with a different body returns 409.

Request body

FieldTypeDescription
namerequired
string
The event name (required, up to 120 characters).
properties
object
Plain text, number and boolean values; objects are dropped.
time
string <date-time>
When it happened. Defaults to now; a value that is not a date is a 400.

Response 201

FieldTypeDescription
objectrequired
string
profileIdrequired
string
namerequired
string
enrolledInFlowsrequired
integer
How many live flows the event started for this person.

Errors

400Malformed or missing parameters
401Bad, missing, or revoked key
402The prepaid balance has nothing left for API requests past the included pool, or the trial requests are used up
403Lacks scope, plan without API access, live key on a trial, test key writing, or feature switched off
404No such resource in this organization
409Idempotency-Key reused with a different body
429Rate limited
500Unexpected server error