Skip to content

Create contact

POST
/v1/contacts
curl --request POST \
--url https://api.postlever.com/v1/contacts \
--header 'Authorization: <Authorization>' \
--header 'Content-Type: application/json' \
--data '{ "email": "user@example.com", "brandIds": [ "497f6eca-6276-4993-bfeb-53cbbbba6f08" ], "attributes": { "first_name": "Alice" } }'

Adds a contact to your contacts. If a contact with the same email already exists the request is rejected with 409 contact_exists. Please use the attributes present in the contact schema defined in the portal. This can also be retrieve from GET /v1/contact-schema.

Handling an email you have sent before

Send duplicateContactStrategy and an existing contact is merged into rather than rejected.

duplicateContactStrategy Attributes Brands
omitted Rejected with 409 contact_exists. Nothing.
overwrite Every attribute you send is set, filling blanks or replacing current values. Attributes you don’t send keep their value. brandIds are added to its brands, or replace them if overwriteBrands is true.
keep Only blank attributes are filled in; current values stay. brandIds are added to its brands.
skip The contact is left as it is, and the request succeeds. Untouched.

An attribute sent as an empty string counts as not sent, so it never clears a value; use PATCH /v1/contacts/{emailMd5} with null to clear one. A contact’s hard bounce, the date it was first added and how it was first imported are always kept, whatever you send.

Disabled contacts

A disabled contact is left disabled and the request fails with 409 contact_exists. To bring it back, send restoreDisabled: true with a duplicateContactStrategy. The contact is enabled again, and:

duplicateContactStrategy Attributes Brands
overwrite Every attribute you send is set, filling blanks or replacing current values. Attributes you don’t send keep their value. brandIds are added to its brands, or replace them if overwriteBrands is true.
keep Only blank attributes are filled in; current values stay. brandIds are added to its brands.
skip Only the attributes you send; any others are cleared. Replaced by brandIds if sent, otherwise kept.
Media typeapplication/json

The contact to create. Schema attribute values are provided in the attributes object; attribute keys must exist in your account’s contact schema (see GET /v1/contact-schema). The brand attribute key is rejected; a contact’s brands are set via brandIds. Derived name:subKey keys (e.g. email:md5) are computed by PostLever and rejected. An empty-string value is treated as not provided: the attribute is left off the created contact rather than rejected. PATCH differs and rejects it.

object
email
required

The contact’s email address in plaintext. The contact identity is derived from it and cannot be changed later.

string format: email
brandIds

Optional list of brands to add to the contact. Every brand must be an existing brand in your account. Retreive brand ids from GET /v1/brands

Array<string>
>= 1 items <= 100 items unique items
publishBrandSubscribeEvents

When true, a brand-subscribe event is recorded for each brand the contact is assigned on creation, triggering any downstream subscribe automations. Defaults to true; set to false to add the brands without firing automations.

boolean
default: true
attributes

Custom schema attribute values, keyed by attribute name. An attribute this object does not carry is left unanswered rather than given a value: a boolean attribute you omit is absent from the contact, which is not the same as sending false. Each text value holds at most 255 characters.

object
key
additional properties
One of:
string
<= 255 characters
duplicateContactStrategy

What to do if a contact with this email already exists. If omitted, the request fails with 409 contact_exists.

  • overwrite: set every attribute you send; the ones you don’t send keep their value.
  • keep: only fill in attributes the contact doesn’t have yet.
  • skip: leave the contact unchanged.
string
Allowed values: overwrite keep skip
overwriteBrands

By default, brandIds are added to the contact’s existing brands. Set to true to replace them instead. Only applies with overwrite.

boolean
restoreDisabled

Set to true to enable a disabled contact again instead of failing with 409 contact_exists. Requires duplicateContactStrategy, which decides how its attributes are merged. See “Disabled contacts” in the endpoint description.

boolean

Example

{
"email": "user@example.com",
"brandIds": [
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
],
"attributes": {
"first_name": "Alice"
}
}

The contact. Returned when it was created, and, with duplicateContactStrategy set, also when an existing contact was merged into or left unchanged by skip.

Media typeapplication/json

A contact in your account.

object
email
required

The contact’s email address.

string format: email
emailMd5
required

The contact identity, md5(lower(email)), used in single-contact request paths.

string
/^[a-f0-9]{32}$/
attributes
required

Schema attribute values keyed by attribute name. An attribute the contact has no value for is absent from this object, so a missing boolean key means no answer was ever recorded for it and is distinct from false. Attributes of type email additionally expand into one read-only name:subKey entry per derived sub-attribute (e.g. name:md5, name:domain). The identity email and the brands are surfaced via the dedicated email and brandIds fields instead of appearing here.

object
key
additional properties
One of:
string
brandIds
required

Ids of the brands the contact is assigned to. May include ids of brands that have since been deleted from the account; resolve names via GET /v1/contacts/{emailMd5}/brands or GET /v1/brands.

Array<string>
enabled
required

False when the contact has been disabled via POST /v1/contacts/{emailMd5}/disable.

boolean
createdAt
required

Timestamp at which the contact was first added.

string format: date-time

Example

{
"email": "user@example.com",
"emailMd5": "b58996c504c5638798eb6b511e6f49af",
"attributes": {
"first_name": "Alice"
},
"brandIds": [
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
],
"enabled": true,
"createdAt": "2026-06-12T00:00:00Z"
}

Invalid request payload. Details are provided in the error response.

Media typeapplication/json

Error envelope returned by every v1 endpoint for failures, following RFC 9457 Problem Details with code and errors extensions.

object
type
required

URI identifying the problem type; dereferences to its documentation.

string format: uri
status
required

HTTP status code applicable to this problem.

integer
title
required

Short, human-readable summary of the problem type.

string
detail
required

Detailed explanation specific to this occurrence.

string
code
required

Error code identifying the specific error condition.

string
Allowed values: invalid_request_error authentication_error permission_error not_found_error conflict_error api_error contact_exists operation_in_progress
instance

URI reference identifying this specific occurrence (the request URI).

string format: uri-reference
errors

Provides additional information when the error relates to specific request fields.

Array<object>
object
detail
required

Detailed explanation for this specific field error.

string
pointer

JSON Pointer (RFC 6901) to the request body value that caused the error (e.g. /email, /attributes/firstName).

string
parameter

The URI query parameter that caused the error (e.g. pageSize, name[invalid]).

string

Example

{
"type": "https://docs.postlever.com/error-codes#invalid_request_error",
"status": 400,
"title": "Invalid request",
"detail": "\"nickname\" is not an attribute in the contact schema",
"code": "invalid_request_error",
"instance": "/v1/contacts",
"errors": [
{
"detail": "\"nickname\" is not an attribute in the contact schema",
"pointer": "/attributes/nickname"
}
]
}

Missing or invalid API key.

Media typeapplication/json

Error envelope returned by every v1 endpoint for failures, following RFC 9457 Problem Details with code and errors extensions.

object
type
required

URI identifying the problem type; dereferences to its documentation.

string format: uri
status
required

HTTP status code applicable to this problem.

integer
title
required

Short, human-readable summary of the problem type.

string
detail
required

Detailed explanation specific to this occurrence.

string
code
required

Error code identifying the specific error condition.

string
Allowed values: invalid_request_error authentication_error permission_error not_found_error conflict_error api_error contact_exists operation_in_progress
instance

URI reference identifying this specific occurrence (the request URI).

string format: uri-reference
errors

Provides additional information when the error relates to specific request fields.

Array<object>
object
detail
required

Detailed explanation for this specific field error.

string
pointer

JSON Pointer (RFC 6901) to the request body value that caused the error (e.g. /email, /attributes/firstName).

string
parameter

The URI query parameter that caused the error (e.g. pageSize, name[invalid]).

string

Example

{
"type": "https://docs.postlever.com/error-codes#authentication_error",
"status": 401,
"title": "Authentication failed",
"detail": "Missing or invalid API key",
"code": "authentication_error",
"instance": "/v1/contacts"
}

Permission denied.

Media typeapplication/json

Error envelope returned by every v1 endpoint for failures, following RFC 9457 Problem Details with code and errors extensions.

object
type
required

URI identifying the problem type; dereferences to its documentation.

string format: uri
status
required

HTTP status code applicable to this problem.

integer
title
required

Short, human-readable summary of the problem type.

string
detail
required

Detailed explanation specific to this occurrence.

string
code
required

Error code identifying the specific error condition.

string
Allowed values: invalid_request_error authentication_error permission_error not_found_error conflict_error api_error contact_exists operation_in_progress
instance

URI reference identifying this specific occurrence (the request URI).

string format: uri-reference
errors

Provides additional information when the error relates to specific request fields.

Array<object>
object
detail
required

Detailed explanation for this specific field error.

string
pointer

JSON Pointer (RFC 6901) to the request body value that caused the error (e.g. /email, /attributes/firstName).

string
parameter

The URI query parameter that caused the error (e.g. pageSize, name[invalid]).

string

Example

{
"type": "https://docs.postlever.com/error-codes#permission_error",
"status": 403,
"title": "Permission denied",
"detail": "api key required",
"code": "permission_error",
"instance": "/v1/contacts"
}

Returned with code: contact_exists when a contact with this email already exists and duplicateContactStrategy was not sent, when the contact is disabled and restoreDisabled was not sent, or when the email belongs to a seed. Also returned with code: operation_in_progress when a bulk contact operation or schema change is in flight for the account. In that case retry after the number of seconds given in the Retry-After header.

Media typeapplication/json

Error envelope returned by every v1 endpoint for failures, following RFC 9457 Problem Details with code and errors extensions.

object
type
required

URI identifying the problem type; dereferences to its documentation.

string format: uri
status
required

HTTP status code applicable to this problem.

integer
title
required

Short, human-readable summary of the problem type.

string
detail
required

Detailed explanation specific to this occurrence.

string
code
required

Error code identifying the specific error condition.

string
Allowed values: invalid_request_error authentication_error permission_error not_found_error conflict_error api_error contact_exists operation_in_progress
instance

URI reference identifying this specific occurrence (the request URI).

string format: uri-reference
errors

Provides additional information when the error relates to specific request fields.

Array<object>
object
detail
required

Detailed explanation for this specific field error.

string
pointer

JSON Pointer (RFC 6901) to the request body value that caused the error (e.g. /email, /attributes/firstName).

string
parameter

The URI query parameter that caused the error (e.g. pageSize, name[invalid]).

string

Examples

A contact with this email already exists

{
"type": "https://docs.postlever.com/error-codes#contact_exists",
"status": 409,
"title": "Conflict",
"detail": "A contact with this email already exists",
"code": "contact_exists",
"instance": "/v1/contacts"
}
Retry-After
integer

Seconds to wait before retrying. Present only when code is operation_in_progress.