Reference

Contacts

People you might message. Idempotent on email within a workspace; bulk endpoints exist for high-volume integrations.

List contact import jobs

get /v1/contact_imports
curl -X GET "https://api.clement.so/v1/contact_imports" \
  -H "Authorization: Bearer $CLEMENT_API_KEY"

Query parameters

  • limit integer
  • starting_after string
  • ending_before string

Response200

OK

Property Type Description
object required enum (1)
"list"
data required array<ContactImport>
has_more required boolean
next_cursor required string | null
prev_cursor required string | null
Example response
{
  "object": "list",
  "data": [
    {
      "id": "imp_01HZ8X3J9K7P2QV6R5N4M3T2LE",
      "object": "contact_import",
      "mode": "live",
      "status": "succeeded",
      "total_rows": 1850,
      "succeeded_rows": 1842,
      "failed_rows": 8,
      "errors": [
        {
          "row": 17,
          "email": "not-an-email",
          "error": {
            "type": "invalid_request_error",
            "code": "invalid_email",
            "message": "Email is missing or malformed"
          }
        }
      ],
      "audience_id": "aud_01HZ8X3J9K7P2QV6R5N4M3T2L3",
      "audience_created": false,
      "created_at": "2026-05-02T16:00:00Z",
      "started_at": "2026-05-02T16:00:01Z",
      "completed_at": "2026-05-02T16:00:43Z"
    }
  ],
  "has_more": false,
  "next_cursor": "string",
  "prev_cursor": "string"
}

Errors

  • 400 Invalid request
  • 401 Authentication failed
  • 403 Insufficient scope
  • 404 Not found
  • 409 Conflict
  • 422 Validation failed
  • 429 Rate limited

See Errors for the full envelope and per-code reference.

Bulk-import contacts from a CSV

post /v1/contact_imports

v1 processes synchronously; the response is the completed (or failed) import job. Larger files (>50k rows) will move to async polling once worker support lands; the resource shape is forward-compatible with `status: queued`. `?dry_run=true` parses + validates the CSV without writing any contacts, audience rows, or import_jobs row. Useful for agents that want to surface row-level errors to a human before committing.

curl -X POST "https://api.clement.so/v1/contact_imports" \
  -H "Authorization: Bearer $CLEMENT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

Query parameters

  • dry_run string

Response200

Dry-run result (only when `?dry_run=true`)

Property Type Description
id required string
Example: "dryrun_a1b2c3d4"
object required enum (1)
"contact_import_dry_run"
mode required enum (2)
"live""test"
total_rows required integer
valid_rows required integer Rows that would be upserted on a real run. Duplicates within the file are excluded; existing-email upserts are still counted (they'd no-op).
invalid_rows required integer
errors required array<object>
Show properties
Property Type Description
row required integer
email required string | null
error required object
Show properties
Property Type Description
type required string
code required string
message required string
Example response
{
  "id": "dryrun_a1b2c3d4",
  "object": "contact_import_dry_run",
  "mode": "live",
  "total_rows": 0,
  "valid_rows": 0,
  "invalid_rows": 0,
  "errors": [
    {
      "row": 0,
      "email": "alice@example.com",
      "error": {
        "type": "string",
        "code": "string",
        "message": "string"
      }
    }
  ]
}

Errors

  • 400 Invalid request
  • 401 Authentication failed
  • 403 Insufficient scope
  • 404 Not found
  • 409 Conflict
  • 422 Validation failed
  • 429 Rate limited

See Errors for the full envelope and per-code reference.

Retrieve a contact import job

get /v1/contact_imports/{id}
curl -X GET "https://api.clement.so/v1/contact_imports/obj_01HZ8X3J9K7P2QV6R5N4M3T2L1" \
  -H "Authorization: Bearer $CLEMENT_API_KEY"

Path parameters

  • id string required

Response200

OK

Property Type Description
id required string
object required enum (1)
"contact_import"
mode required enum (2)
"live""test"
status required enum (4)
"queued""processing""succeeded""failed"
total_rows required integer
succeeded_rows required integer
failed_rows required integer
errors required array<object>
Show properties
Property Type Description
row required integer
email required string | null
error required object
Show properties
Property Type Description
type required string
code required string
message required string
audience_id required string | null
audience_created required boolean
created_at required string (date-time)
started_at required string (date-time) | null
completed_at required string (date-time) | null
Example response
{
  "id": "imp_01HZ8X3J9K7P2QV6R5N4M3T2LE",
  "object": "contact_import",
  "mode": "live",
  "status": "succeeded",
  "total_rows": 1850,
  "succeeded_rows": 1842,
  "failed_rows": 8,
  "errors": [
    {
      "row": 17,
      "email": "not-an-email",
      "error": {
        "type": "invalid_request_error",
        "code": "invalid_email",
        "message": "Email is missing or malformed"
      }
    }
  ],
  "audience_id": "aud_01HZ8X3J9K7P2QV6R5N4M3T2L3",
  "audience_created": false,
  "created_at": "2026-05-02T16:00:00Z",
  "started_at": "2026-05-02T16:00:01Z",
  "completed_at": "2026-05-02T16:00:43Z"
}

Errors

  • 400 Invalid request
  • 401 Authentication failed
  • 403 Insufficient scope
  • 404 Not found
  • 409 Conflict
  • 422 Validation failed
  • 429 Rate limited

See Errors for the full envelope and per-code reference.

List contacts

get /v1/contacts
curl -X GET "https://api.clement.so/v1/contacts" \
  -H "Authorization: Bearer $CLEMENT_API_KEY"

Query parameters

  • limit integer
  • starting_after string
  • ending_before string
  • email string
  • q string
  • global_status string
  • lead_status string

Response200

OK

Property Type Description
object required enum (1)
"list"
data required array<Contact>
has_more required boolean
next_cursor required string | null
prev_cursor required string | null
Example response
{
  "object": "list",
  "data": [
    {
      "id": "con_01HZ8X3J9K7P2QV6R5N4M3T2L2",
      "object": "contact",
      "mode": "live",
      "email": "alice@example.com",
      "attributes": {
        "first_name": "Alice",
        "company": "Acme",
        "title": "VP Eng"
      },
      "global_status": "ok",
      "lead_status": null,
      "created_at": "2026-04-20T10:14:00Z",
      "updated_at": "2026-04-20T10:14:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": "string",
  "prev_cursor": "string"
}

Errors

  • 400 Invalid request
  • 401 Authentication failed
  • 403 Insufficient scope
  • 404 Not found
  • 409 Conflict
  • 422 Validation failed
  • 429 Rate limited

See Errors for the full envelope and per-code reference.

Create a contact (idempotent on email)

post /v1/contacts

Returns the existing contact (HTTP 200) when the email is already in this workspace. Otherwise creates and returns the new contact (HTTP 201).

curl -X POST "https://api.clement.so/v1/contacts" \
  -H "Authorization: Bearer $CLEMENT_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
      "email": "alice@example.com",
      "attributes": {},
      "global_status": "ok"
    }'

Request body

Property Type Description
email required string (email)
attributes object
global_status enum (4)
"ok""unsubscribed""bounced""blacklisted"

Response200

Existing contact returned

Property Type Description
id required string
object required enum (1)
"contact"
mode required enum (2)
"live""test"
email required string (email)
attributes required object
global_status required enum (4)
"ok""unsubscribed""bounced""blacklisted"
lead_status required enum (3) | null Read-only here; set with POST /v1/contacts/{id}/lead_status. The workflow tag a member gave the lead after a reply. Stored as `attributes.lead_classification`.
"interested""meeting_booked""not_interested"
created_at required string (date-time)
updated_at required string (date-time)
Example response
{
  "id": "con_01HZ8X3J9K7P2QV6R5N4M3T2L2",
  "object": "contact",
  "mode": "live",
  "email": "alice@example.com",
  "attributes": {
    "first_name": "Alice",
    "company": "Acme",
    "title": "VP Eng"
  },
  "global_status": "ok",
  "lead_status": null,
  "created_at": "2026-04-20T10:14:00Z",
  "updated_at": "2026-04-20T10:14:00Z"
}

Errors

  • 400 Invalid request
  • 401 Authentication failed
  • 403 Insufficient scope
  • 404 Not found
  • 409 Conflict
  • 422 Validation failed
  • 429 Rate limited

See Errors for the full envelope and per-code reference.

Create up to 1,000 contacts in one call

post /v1/contacts/batch

Per-row idempotency on email — existing contacts are returned alongside newly-created ones. Validation failures are reported per-row in `errors`; partial success is the norm.

curl -X POST "https://api.clement.so/v1/contacts/batch" \
  -H "Authorization: Bearer $CLEMENT_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
      "contacts": [
        {
          "email": "alice@example.com",
          "attributes": {},
          "global_status": "ok"
        }
      ]
    }'

Request body

Property Type Description
contacts required array<ContactCreate>

Response200

Result

Property Type Description
object required enum (1)
"batch_result"
created required array<Contact>
errors required array<object>
Show properties
Property Type Description
index required integer
email required string
error required object
Show properties
Property Type Description
type required string
code required string
message required string
Example response
{
  "object": "batch_result",
  "created": [
    {
      "id": "con_01HZ8X3J9K7P2QV6R5N4M3T2L2",
      "object": "contact",
      "mode": "live",
      "email": "alice@example.com",
      "attributes": {
        "first_name": "Alice",
        "company": "Acme",
        "title": "VP Eng"
      },
      "global_status": "ok",
      "lead_status": null,
      "created_at": "2026-04-20T10:14:00Z",
      "updated_at": "2026-04-20T10:14:00Z"
    }
  ],
  "errors": [
    {
      "index": 0,
      "email": "alice@example.com",
      "error": {
        "type": "string",
        "code": "string",
        "message": "string"
      }
    }
  ]
}

Errors

  • 400 Invalid request
  • 401 Authentication failed
  • 403 Insufficient scope
  • 404 Not found
  • 409 Conflict
  • 422 Validation failed
  • 429 Rate limited

See Errors for the full envelope and per-code reference.

Retrieve a contact

get /v1/contacts/{id}
curl -X GET "https://api.clement.so/v1/contacts/obj_01HZ8X3J9K7P2QV6R5N4M3T2L1" \
  -H "Authorization: Bearer $CLEMENT_API_KEY"

Path parameters

  • id string required

Response200

OK

Property Type Description
id required string
object required enum (1)
"contact"
mode required enum (2)
"live""test"
email required string (email)
attributes required object
global_status required enum (4)
"ok""unsubscribed""bounced""blacklisted"
lead_status required enum (3) | null Read-only here; set with POST /v1/contacts/{id}/lead_status. The workflow tag a member gave the lead after a reply. Stored as `attributes.lead_classification`.
"interested""meeting_booked""not_interested"
created_at required string (date-time)
updated_at required string (date-time)
Example response
{
  "id": "con_01HZ8X3J9K7P2QV6R5N4M3T2L2",
  "object": "contact",
  "mode": "live",
  "email": "alice@example.com",
  "attributes": {
    "first_name": "Alice",
    "company": "Acme",
    "title": "VP Eng"
  },
  "global_status": "ok",
  "lead_status": null,
  "created_at": "2026-04-20T10:14:00Z",
  "updated_at": "2026-04-20T10:14:00Z"
}

Errors

  • 400 Invalid request
  • 401 Authentication failed
  • 403 Insufficient scope
  • 404 Not found
  • 409 Conflict
  • 422 Validation failed
  • 429 Rate limited

See Errors for the full envelope and per-code reference.

Update a contact

patch /v1/contacts/{id}
curl -X PATCH "https://api.clement.so/v1/contacts/obj_01HZ8X3J9K7P2QV6R5N4M3T2L1" \
  -H "Authorization: Bearer $CLEMENT_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
      "attributes": {},
      "global_status": "ok"
    }'

Path parameters

  • id string required

Request body

Property Type Description
attributes object Merged into existing attributes. Set a key to `null` to remove it from the contact.
global_status enum (4)
"ok""unsubscribed""bounced""blacklisted"

Response200

Updated

Property Type Description
id required string
object required enum (1)
"contact"
mode required enum (2)
"live""test"
email required string (email)
attributes required object
global_status required enum (4)
"ok""unsubscribed""bounced""blacklisted"
lead_status required enum (3) | null Read-only here; set with POST /v1/contacts/{id}/lead_status. The workflow tag a member gave the lead after a reply. Stored as `attributes.lead_classification`.
"interested""meeting_booked""not_interested"
created_at required string (date-time)
updated_at required string (date-time)
Example response
{
  "id": "con_01HZ8X3J9K7P2QV6R5N4M3T2L2",
  "object": "contact",
  "mode": "live",
  "email": "alice@example.com",
  "attributes": {
    "first_name": "Alice",
    "company": "Acme",
    "title": "VP Eng"
  },
  "global_status": "ok",
  "lead_status": null,
  "created_at": "2026-04-20T10:14:00Z",
  "updated_at": "2026-04-20T10:14:00Z"
}

Errors

  • 400 Invalid request
  • 401 Authentication failed
  • 403 Insufficient scope
  • 404 Not found
  • 409 Conflict
  • 422 Validation failed
  • 429 Rate limited

See Errors for the full envelope and per-code reference.

Delete a contact

delete /v1/contacts/{id}

Hard delete. Cascades to `campaign_contacts`; historical `sends` keep their email snapshot.

curl -X DELETE "https://api.clement.so/v1/contacts/obj_01HZ8X3J9K7P2QV6R5N4M3T2L1" \
  -H "Authorization: Bearer $CLEMENT_API_KEY"

Path parameters

  • id string required

Response200

Deleted

Property Type Description
id required string
object required enum (1)
"contact"
mode required enum (2)
"live""test"
email required string (email)
attributes required object
global_status required enum (4)
"ok""unsubscribed""bounced""blacklisted"
lead_status required enum (3) | null Read-only here; set with POST /v1/contacts/{id}/lead_status. The workflow tag a member gave the lead after a reply. Stored as `attributes.lead_classification`.
"interested""meeting_booked""not_interested"
created_at required string (date-time)
updated_at required string (date-time)
Example response
{
  "id": "con_01HZ8X3J9K7P2QV6R5N4M3T2L2",
  "object": "contact",
  "mode": "live",
  "email": "alice@example.com",
  "attributes": {
    "first_name": "Alice",
    "company": "Acme",
    "title": "VP Eng"
  },
  "global_status": "ok",
  "lead_status": null,
  "created_at": "2026-04-20T10:14:00Z",
  "updated_at": "2026-04-20T10:14:00Z"
}

Errors

  • 400 Invalid request
  • 401 Authentication failed
  • 403 Insufficient scope
  • 404 Not found
  • 409 Conflict
  • 422 Validation failed
  • 429 Rate limited

See Errors for the full envelope and per-code reference.

Set a contact's lead status

post /v1/contacts/{id}/lead_status

Tags the lead `interested`, `meeting_booked` or `not_interested`, as the dashboard's inbox does after a reply. `not_interested` also stops the sequence: the contact's active or replied enrollments (only the one in `campaign_id` when given) become `unsubscribed`. Emits `contact.lead_status_changed` when the status changes.

curl -X POST "https://api.clement.so/v1/contacts/obj_01HZ8X3J9K7P2QV6R5N4M3T2L1/lead_status" \
  -H "Authorization: Bearer $CLEMENT_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
      "lead_status": "interested",
      "campaign_id": "cmp_01HZ8X3J9K7P2QV6R5N4M3T2L4"
    }'

Path parameters

  • id string required

Request body

Property Type Description
lead_status required enum (3)
"interested""meeting_booked""not_interested"
campaign_id string The campaign the reply came from: limits `not_interested` to that enrollment and is recorded on the event.

Response200

Updated

Property Type Description
id required string
object required enum (1)
"contact"
mode required enum (2)
"live""test"
email required string (email)
attributes required object
global_status required enum (4)
"ok""unsubscribed""bounced""blacklisted"
lead_status required enum (3) | null Read-only here; set with POST /v1/contacts/{id}/lead_status. The workflow tag a member gave the lead after a reply. Stored as `attributes.lead_classification`.
"interested""meeting_booked""not_interested"
created_at required string (date-time)
updated_at required string (date-time)
Example response
{
  "id": "con_01HZ8X3J9K7P2QV6R5N4M3T2L2",
  "object": "contact",
  "mode": "live",
  "email": "alice@example.com",
  "attributes": {
    "first_name": "Alice",
    "company": "Acme",
    "title": "VP Eng"
  },
  "global_status": "ok",
  "lead_status": null,
  "created_at": "2026-04-20T10:14:00Z",
  "updated_at": "2026-04-20T10:14:00Z"
}

Errors

  • 400 Invalid request
  • 401 Authentication failed
  • 403 Insufficient scope
  • 404 Not found
  • 409 Conflict
  • 422 Validation failed
  • 429 Rate limited

See Errors for the full envelope and per-code reference.