Skip to the documentation

Clients

The people you work for: add them, edit them, give them access to what you share.

List clients

GET/api/v1/clients

Your clients, newest first. Archived clients stay out unless you ask. Pages by cursor, 20 at a time and up to 50: follow links.next until it is null.

An API key carrying the scope named here, or a signed-in session.

Scope
clients:read
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Parameters

NameInTypeRequiredDescription
statusQuery"active" | "archived" | "all"Optionalactive (the default) leaves archived clients out, archived lists only them, all lists both. It stays on the next page's link.
limitQueryintegerOptionalHow many to return: 1 to 50, 20 when absent. A number outside that range is clamped; text is ignored.
cursorQuerystringOptionalWhere the last page ended: the cursor inside the previous page's links.next. Pass links as given; a cursor you edit is refused.

Examples

curl "https://liviamatch.com/api/v1/clients" \
  -H "Authorization: Bearer $LIVIA_API_KEY"

Responses

200

One page of clients.

Two clients
{
  "data": [
    {
      "id": "4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24",
      "name": "Tunde Bello",
      "email": "tunde.bello@example.com",
      "note": null,
      "phone": null,
      "archivedAt": null,
      "createdAt": "2026-10-06T09:41:03.118Z",
      "hasAccess": false,
      "links": {
        "self": "/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24",
        "access": "/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24/access"
      }
    },
    {
      "id": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
      "name": "Amara Okafor",
      "email": "amara.okafor@example.com",
      "note": "Relocating from Boston in January. Two kids, one dog.",
      "phone": "+16155550142",
      "archivedAt": null,
      "createdAt": "2026-10-01T15:12:40.221Z",
      "hasAccess": true,
      "links": {
        "self": "/api/v1/clients/9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
        "access": "/api/v1/clients/9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28/access"
      }
    }
  ],
  "links": {
    "next": null
  }
}
Fields (14)
FieldTypeDescription
dataobject[]
data[].idstring (uuid)
data[].namestring
data[].emailstring | nullWhere to reach them, or null when none is on file.
data[].notestring | nullYour own note about them, or null.
data[].phonestring | nullTheir mobile number in E.164, or null. A ready match is texted to it when you ask to send it to them.
data[].archivedAtstring (date-time) | nullWhen they were archived, or null for an active client.
data[].createdAtstring (date-time)
data[].hasAccessbooleanWhether they can sign in to see what you share: an invitation was sent, or an access code made. Needed before you share with them.
data[].linksobject
data[].links.selfstring
data[].links.accessstringWhere to POST to give them access.
linksobject
links.nextstring | nullThe URL of the next page, or null when this is the last. Follow it as given.

Errors

StatusCodeWhen
400invalidThe status is not active, archived or all.
400invalid-cursorThe cursor is not one a page linked to.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal

Add a client

POST/api/v1/clients

Adds a client and answers 201 with them and a Location. The server picks the id.

A POST that times out may or may not have landed, and a second one adds a second client. To make a retry safe, choose the id yourself and use PUT /api/v1/clients/{clientId}: the same id with the same body lands once.

An API key carrying the scope named here, or a signed-in session.

Scope
clients:write
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Request body

The client. Only name is required. Unknown fields are refused.

Fields (4)
FieldTypeRequiredDescription
namestringRequiredThe client's name: 1 to 100 characters once trimmed.1 to 100 characters
emailstring | nullOptionalWhere to reach them, or null. Needed before you can give them access to a share.at most 254 characters, default null
notestring | nullOptionalYour own note about them, up to 2000 characters, or null.at most 2000 characters, default null
phonestring | nullOptionalTheir mobile number, kept as E.164 (a 10-digit US number gains +1), or null. A ready match is texted to it when you ask to send it to them.at most 40 characters
Examples
{
  "name": "Tunde Bello",
  "email": "tunde.bello@example.com"
}

Examples

curl -X POST "https://liviamatch.com/api/v1/clients" \
  -H "Authorization: Bearer $LIVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Tunde Bello",
  "email": "tunde.bello@example.com"
}'

Responses

201

The client was added.

HeadersLocation

A new client
{
  "data": {
    "id": "4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24",
    "name": "Tunde Bello",
    "email": "tunde.bello@example.com",
    "note": null,
    "phone": null,
    "archivedAt": null,
    "createdAt": "2026-10-06T09:41:03.118Z",
    "hasAccess": false,
    "links": {
      "self": "/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24",
      "access": "/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24/access"
    }
  }
}
Fields (12)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.namestring
data.emailstring | nullWhere to reach them, or null when none is on file.
data.notestring | nullYour own note about them, or null.
data.phonestring | nullTheir mobile number in E.164, or null. A ready match is texted to it when you ask to send it to them.
data.archivedAtstring (date-time) | nullWhen they were archived, or null for an active client.
data.createdAtstring (date-time)
data.hasAccessbooleanWhether they can sign in to see what you share: an invitation was sent, or an access code made. Needed before you share with them.
data.linksobject
data.links.selfstring
data.links.accessstringWhere to POST to give them access.

Errors

StatusCodeWhen
400invalidThe body failed validation; issues names each field.
400invalid-jsonThe body is empty or not JSON.
413too-largeThe body is over 64 KiB.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal

Read a client

GET/api/v1/clients/{clientId}

One of your clients, archived or not, and whether they can sign in to see what you share.

An API key carrying the scope named here, or a signed-in session.

Scope
clients:read
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Parameters

NameInTypeRequiredDescription
clientIdPathstring (uuid)RequiredThe client's id.

Examples

curl "https://liviamatch.com/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24" \
  -H "Authorization: Bearer $LIVIA_API_KEY"

Responses

200

The client.

A client with access
{
  "data": {
    "id": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
    "name": "Amara Okafor",
    "email": "amara.okafor@example.com",
    "note": "Relocating from Boston in January. Two kids, one dog.",
    "phone": "+16155550142",
    "archivedAt": null,
    "createdAt": "2026-10-01T15:12:40.221Z",
    "hasAccess": true,
    "links": {
      "self": "/api/v1/clients/9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
      "access": "/api/v1/clients/9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28/access"
    }
  }
}
Fields (12)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.namestring
data.emailstring | nullWhere to reach them, or null when none is on file.
data.notestring | nullYour own note about them, or null.
data.phonestring | nullTheir mobile number in E.164, or null. A ready match is texted to it when you ask to send it to them.
data.archivedAtstring (date-time) | nullWhen they were archived, or null for an active client.
data.createdAtstring (date-time)
data.hasAccessbooleanWhether they can sign in to see what you share: an invitation was sent, or an access code made. Needed before you share with them.
data.linksobject
data.links.selfstring
data.links.accessstringWhere to POST to give them access.

Errors

StatusCodeWhen
404not-foundNo such client in your workspace.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal

Save a client at an id

PUT/api/v1/clients/{clientId}

Saves a client at an id you choose, which makes a retry land once: 201 when the id is new, 200 when it names one of your clients, whose name, email and note become what you sent (an email or note you leave out is cleared).

To change one field, use PATCH. An id that belongs to someone else's client is 409, and nothing of theirs is touched.

An API key carrying the scope named here, or a signed-in session.

Scope
clients:write
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Parameters

NameInTypeRequiredDescription
clientIdPathstring (uuid)RequiredThe client's id.

Request body

The whole client, as for adding one.

Fields (4)
FieldTypeRequiredDescription
namestringRequiredThe client's name: 1 to 100 characters once trimmed.1 to 100 characters
emailstring | nullOptionalWhere to reach them, or null. Needed before you can give them access to a share.at most 254 characters, default null
notestring | nullOptionalYour own note about them, up to 2000 characters, or null.at most 2000 characters, default null
phonestring | nullOptionalTheir mobile number, kept as E.164 (a 10-digit US number gains +1), or null. A ready match is texted to it when you ask to send it to them.at most 40 characters
Examples
{
  "name": "Tunde Bello",
  "email": "tunde.bello@example.com",
  "note": "Prefers email."
}

Examples

curl -X PUT "https://liviamatch.com/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24" \
  -H "Authorization: Bearer $LIVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Tunde Bello",
  "email": "tunde.bello@example.com",
  "note": "Prefers email."
}'

Responses

201

A new client was saved.

HeadersLocation

A new client
{
  "data": {
    "id": "4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24",
    "name": "Tunde Bello",
    "email": "tunde.bello@example.com",
    "note": null,
    "phone": null,
    "archivedAt": null,
    "createdAt": "2026-10-06T09:41:03.118Z",
    "hasAccess": false,
    "links": {
      "self": "/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24",
      "access": "/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24/access"
    }
  }
}
Fields (12)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.namestring
data.emailstring | nullWhere to reach them, or null when none is on file.
data.notestring | nullYour own note about them, or null.
data.phonestring | nullTheir mobile number in E.164, or null. A ready match is texted to it when you ask to send it to them.
data.archivedAtstring (date-time) | nullWhen they were archived, or null for an active client.
data.createdAtstring (date-time)
data.hasAccessbooleanWhether they can sign in to see what you share: an invitation was sent, or an access code made. Needed before you share with them.
data.linksobject
data.links.selfstring
data.links.accessstringWhere to POST to give them access.
200

One of your clients was replaced.

HeadersLocation

A replaced client
{
  "data": {
    "id": "4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24",
    "name": "Tunde Bello",
    "email": "tunde.bello@example.com",
    "note": "Prefers email.",
    "phone": null,
    "archivedAt": null,
    "createdAt": "2026-10-06T09:41:03.118Z",
    "hasAccess": false,
    "links": {
      "self": "/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24",
      "access": "/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24/access"
    }
  }
}
Fields (12)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.namestring
data.emailstring | nullWhere to reach them, or null when none is on file.
data.notestring | nullYour own note about them, or null.
data.phonestring | nullTheir mobile number in E.164, or null. A ready match is texted to it when you ask to send it to them.
data.archivedAtstring (date-time) | nullWhen they were archived, or null for an active client.
data.createdAtstring (date-time)
data.hasAccessbooleanWhether they can sign in to see what you share: an invitation was sent, or an access code made. Needed before you share with them.
data.linksobject
data.links.selfstring
data.links.accessstringWhere to POST to give them access.

Errors

StatusCodeWhen
400invalidThe body failed validation; issues names each field.
400invalid-jsonThe body is empty or not JSON.
413too-largeThe body is over 64 KiB.
409id-unavailableThe id belongs to something that is not yours.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal

Change a client

PATCH/api/v1/clients/{clientId}

Changes the fields you send and leaves the rest. null clears an email or a note. "archived": true archives the client (they leave the default list and everything of theirs is kept) and false restores them. Each change that took hold is a line in the audit trail, naming which fields moved and never their contents.

An API key carrying the scope named here, or a signed-in session.

Scope
clients:write
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Parameters

NameInTypeRequiredDescription
clientIdPathstring (uuid)RequiredThe client's id.

Request body

Any of the fields; at least one.

Fields (5)
FieldTypeRequiredDescription
namestringOptionalA new name.1 to 100 characters
emailstring | nullOptionalA new address, or null to clear it.at most 254 characters
notestring | nullOptionalA new note, or null to clear it.at most 2000 characters
phonestring | nullOptionalA new mobile number, or null to clear it.at most 40 characters
archivedbooleanOptionaltrue archives the client, false restores them. Archiving ends nothing: an archived client still signs in and still sees what was shared.
Examples
{
  "archived": true
}

Examples

curl -X PATCH "https://liviamatch.com/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24" \
  -H "Authorization: Bearer $LIVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "archived": true
}'

Responses

200

The client after the change.

An archived client
{
  "data": {
    "id": "4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24",
    "name": "Tunde Bello",
    "email": "tunde.bello@example.com",
    "note": null,
    "phone": null,
    "archivedAt": "2026-10-06T10:02:55.640Z",
    "createdAt": "2026-10-06T09:41:03.118Z",
    "hasAccess": false,
    "links": {
      "self": "/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24",
      "access": "/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24/access"
    }
  }
}
Fields (12)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.namestring
data.emailstring | nullWhere to reach them, or null when none is on file.
data.notestring | nullYour own note about them, or null.
data.phonestring | nullTheir mobile number in E.164, or null. A ready match is texted to it when you ask to send it to them.
data.archivedAtstring (date-time) | nullWhen they were archived, or null for an active client.
data.createdAtstring (date-time)
data.hasAccessbooleanWhether they can sign in to see what you share: an invitation was sent, or an access code made. Needed before you share with them.
data.linksobject
data.links.selfstring
data.links.accessstringWhere to POST to give them access.

Errors

StatusCodeWhen
404not-foundNo such client in your workspace.
400invalidThe body failed validation; issues names each field.
400invalid-jsonThe body is empty or not JSON.
413too-largeThe body is over 64 KiB.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal

Give a client access

POST/api/v1/clients/{clientId}/access

Gives a client access to what you share with them: records the address they sign in by and emails them a sign-in link naming you, good for three days. A client needs access before you can share a shortlist with them.

The link goes to the email you send, else to the one on the client; with neither there is nobody to send it to (client-needs-email). Sending again sends a fresh link and ends the last. This is the one call here that emails someone, so it needs the shares:write scope.

An API key carrying the scope named here, or a signed-in session.

Scope
shares:write
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Parameters

NameInTypeRequiredDescription
clientIdPathstring (uuid)RequiredThe client's id.

Request body

Optional. The address to send the link to, when it is not the one on the client. The body is optional.

Fields (1)
FieldTypeRequiredDescription
emailstringOptionalThe address to send the sign-in link to. Left out, the client's own address is used. Giving one replaces the address their access signs in by.at most 254 characters
Examples
{
  "email": "tunde.bello@example.com"
}

Examples

curl -X POST "https://liviamatch.com/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24/access" \
  -H "Authorization: Bearer $LIVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "tunde.bello@example.com"
}'

Responses

200

The invitation was sent; the client now has access.

A client with access
{
  "data": {
    "id": "4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24",
    "name": "Tunde Bello",
    "email": "tunde.bello@example.com",
    "note": null,
    "phone": null,
    "archivedAt": null,
    "createdAt": "2026-10-06T09:41:03.118Z",
    "hasAccess": true,
    "links": {
      "self": "/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24",
      "access": "/api/v1/clients/4b9e2d71-0c58-4a36-8d1f-7e3a5c9b0f24/access"
    }
  }
}
Fields (12)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.namestring
data.emailstring | nullWhere to reach them, or null when none is on file.
data.notestring | nullYour own note about them, or null.
data.phonestring | nullTheir mobile number in E.164, or null. A ready match is texted to it when you ask to send it to them.
data.archivedAtstring (date-time) | nullWhen they were archived, or null for an active client.
data.createdAtstring (date-time)
data.hasAccessbooleanWhether they can sign in to see what you share: an invitation was sent, or an access code made. Needed before you share with them.
data.linksobject
data.links.selfstring
data.links.accessstringWhere to POST to give them access.

Errors

StatusCodeWhen
404not-foundNo such client in your workspace.
400invalidThe body failed validation; issues names each field.
400invalid-jsonThe body is empty or not JSON.
413too-largeThe body is over 64 KiB.
409client-needs-emailThe client has no email on file and none was sent.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal