Dashly Docs

Contacts

`/contacts`

List contacts

GET
/contacts

One page of records, newest first unless you say otherwise, with the total count in meta so you know how far to paginate.

Required scope: contacts:read.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Query Parameters

page?integer

1-based. meta.totalPages says how many there are.

Range1 <= value
Default1
per_page?integer

Rows per page. A value above 200 returns 400 - never a silent clamp.

Range1 <= value <= 200
Default50
sort?string

Prefix with - for descending. An undeclared sort returns 400.

Default"-createdAt"
Value in"createdAt""-createdAt""name""-name"
q?string

Case-insensitive "contains", across: name, email.

filter[isDecisionMaker]?string

Exact match on isDecisionMaker.

Value in"true""false"
filter[lead]?string

false (the default) leaves out the people that only an unconverted lead knows; true lists only them. They join the directory when the lead converts.

Value in"true""false"
filter[clientId]?string

Exact match on clientId.

Response Body

The requested page.

application/json
  1. response
data*array<>
meta*
Example Request
curl -X GET 'https://api.usedashly.com/v1/contacts'
Example Response
{  "data": [    {      "id": "string",      "clientId": "string",      "name": "string",      "firstName": "string",      "lastName": "string",      "email": "string",      "phone": "string",      "role": "string",      "linkedinUrl": "string",      "isDecisionMaker": true,      "createdAt": "2019-08-24T14:15:22Z",      "customFields": {}    }  ],  "meta": {    "page": 0,    "perPage": 0,    "total": 0,    "totalPages": 0  }}

Create a contact

POST
/contacts

Links are given as the target's public id (clientId: "hsbftmp3f5"); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.

Required scope: contacts:write.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Header Parameters

Idempotency-Key?string

A value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.

Length8 <= length <= 255

Request Body

application/json
  1. body
firstName*string
Length1 <= length <= 80
lastName?string
Lengthlength <= 80
email?|null
phone?|

Phone number, stored in E.164 (+33612345678). A national number is read as French; a number that is not valid for its country is refused (validation_failed).

role?|null
linkedinUrl?|null
isDecisionMaker?boolean
clientId?string|null
createdAt?string

When this actually happened, for an import. Past dates only; defaults to now. updatedAt follows it unless the body sets one.

Formatdate-time

Response Body

Created. The body is the new record, as a read would return it.

application/json
  1. response
data*
Example Request
curl -X POST 'https://api.usedashly.com/v1/contacts' \  -H 'Content-Type: application/json' \  -d '{  "firstName": "string"}'
Example Response
{  "data": {    "id": "string",    "clientId": "string",    "name": "string",    "firstName": "string",    "lastName": "string",    "email": "string",    "phone": "string",    "role": "string",    "linkedinUrl": "string",    "isDecisionMaker": true,    "createdAt": "2019-08-24T14:15:22Z",    "customFields": {}  }}

Retrieve a contact

GET
/contacts/{id}

The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 - its existence is not ours to confirm.

Required scope: contacts:read.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Path Parameters

id*string

The record's public id (hsbftmp3f5), as returned in the id field. An internal UUID returns 404.

Response Body

Found.

application/json
  1. response
data*
Example Request
curl -X GET 'https://api.usedashly.com/v1/contacts/string'
Example Response
{  "data": {    "id": "string",    "clientId": "string",    "name": "string",    "firstName": "string",    "lastName": "string",    "email": "string",    "phone": "string",    "role": "string",    "linkedinUrl": "string",    "isDecisionMaker": true,    "createdAt": "2019-08-24T14:15:22Z",    "customFields": {}  }}

Update a contact

PATCH
/contacts/{id}

A partial update: only the fields you send change. One exception - customFields is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.

Required scope: contacts:write.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Path Parameters

id*string

The record's public id (hsbftmp3f5), as returned in the id field. An internal UUID returns 404.

Request Body

application/json
  1. body
firstName?string
Length1 <= length <= 80
lastName?string
Lengthlength <= 80
email?|null
phone?|

Phone number, stored in E.164 (+33612345678). A national number is read as French; a number that is not valid for its country is refused (validation_failed).

role?|null
linkedinUrl?|null
isDecisionMaker?boolean
clientId?string|null

Response Body

Updated. The body is the record as it now stands.

application/json
  1. response
data*
Example Request
curl -X PATCH 'https://api.usedashly.com/v1/contacts/string' \  -H 'Content-Type: application/json' \  -d '{}'
Example Response
{  "data": {    "id": "string",    "clientId": "string",    "name": "string",    "firstName": "string",    "lastName": "string",    "email": "string",    "phone": "string",    "role": "string",    "linkedinUrl": "string",    "isDecisionMaker": true,    "createdAt": "2019-08-24T14:15:22Z",    "customFields": {}  }}

Delete a contact

DELETE
/contacts/{id}

Permanent. The audit log keeps the trace; the record does not come back.

Required scope: contacts:write.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Path Parameters

id*string

The record's public id (hsbftmp3f5), as returned in the id field. An internal UUID returns 404.

Response Body

Deleted. Empty body.

Example Request
curl -X DELETE 'https://api.usedashly.com/v1/contacts/string'
Example Response
Empty

List available actions

GET
/contacts/actions

Every verb this resource answers to, with its target and the JSON Schema of its body - the same contracts this document describes, readable at runtime.

Required scope: contacts:read.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Response Body

The available verbs.

application/json
  1. response
data*array<>
Example Request
curl -X GET 'https://api.usedashly.com/v1/contacts/actions'
Example Response
{  "data": [    {      "name": "string",      "label": "string",      "description": "string",      "target": "item",      "readOnly": true,      "path": "string",      "input": {}    }  ]}
POST
/contacts/{id}/actions/link-object

Creates a relation between this record and a target object (targetType plus the target's public targetId) in the relation graph. Linking the same pair twice does nothing.

Does what the dashboard's linkObjectAction does - same implementation, so the two cannot diverge.

Required scope: contacts:write.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Path Parameters

id*string

The public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.

Header Parameters

Idempotency-Key?string

A value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.

Length8 <= length <= 255

Request Body

application/json
  1. body
targetType*string
Value in"account""contact""project""ticket""deal""user""proposal"
targetId*string
Length1 <= length <= 60

Response Body

Done.

application/json
  1. response
data*unknown

The action's result; its shape depends on the verb.

Example Request
curl -X POST 'https://api.usedashly.com/v1/contacts/string/actions/link-object' \  -H 'Content-Type: application/json' \  -d '{  "targetType": "account",  "targetId": "string"}'
Example Response
{  "data": null}
POST
/contacts/{id}/actions/unlink-object

Removes the relation between this record and the target object in the relation graph. Unlinking a pair that was never linked does nothing. A deal/project pair is unlinked like unlink-project on the deal: the change is audited, so the key must be attached to a user (403 with reason key_not_attached otherwise).

Does what the dashboard's unlinkObjectAction does - same implementation, so the two cannot diverge.

Required scope: contacts:write.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Path Parameters

id*string

The public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.

Header Parameters

Idempotency-Key?string

A value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.

Length8 <= length <= 255

Request Body

application/json
  1. body
targetType*string
Value in"account""contact""project""ticket""deal""user""proposal"
targetId*string
Length1 <= length <= 60

Response Body

Done.

application/json
  1. response
data*unknown

The action's result; its shape depends on the verb.

Example Request
curl -X POST 'https://api.usedashly.com/v1/contacts/string/actions/unlink-object' \  -H 'Content-Type: application/json' \  -d '{  "targetType": "account",  "targetId": "string"}'
Example Response
{  "data": null}
POST
/contacts/{id}/actions/link-account

Links this person to the given client, or updates the job title and the e-mail address they use at that organisation. The first link becomes their primary organisation.

Does what the dashboard's linkContactAccountAction does - same implementation, so the two cannot diverge.

Required scope: contacts:write.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Path Parameters

id*string

The public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.

Header Parameters

Idempotency-Key?string

A value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.

Length8 <= length <= 255

Request Body

application/json
  1. body
clientId*string
Length1 <= length <= 60
title?string
Lengthlength <= 80
email?|string

Response Body

Done.

application/json
  1. response
data*unknown

The action's result; its shape depends on the verb.

Example Request
curl -X POST 'https://api.usedashly.com/v1/contacts/string/actions/link-account' \  -H 'Content-Type: application/json' \  -d '{  "clientId": "string"}'
Example Response
{  "data": null}
POST
/contacts/{id}/actions/unlink-account

Removes the link between this person and the given client. If it was their primary organisation, another link takes over.

Does what the dashboard's unlinkContactAccountAction does - same implementation, so the two cannot diverge.

Required scope: contacts:write.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Path Parameters

id*string

The public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.

Header Parameters

Idempotency-Key?string

A value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.

Length8 <= length <= 255

Request Body

application/json
  1. body
clientId*string
Length1 <= length <= 60

Response Body

Done.

application/json
  1. response
data*unknown

The action's result; its shape depends on the verb.

Example Request
curl -X POST 'https://api.usedashly.com/v1/contacts/string/actions/unlink-account' \  -H 'Content-Type: application/json' \  -d '{  "clientId": "string"}'
Example Response
{  "data": null}
POST
/contacts/{id}/actions/set-primary-account

Makes the given client this person's primary organisation - the one single-company views show. The other links are kept.

Does what the dashboard's setPrimaryAccountAction does - same implementation, so the two cannot diverge.

Required scope: contacts:write.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Path Parameters

id*string

The public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.

Header Parameters

Idempotency-Key?string

A value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.

Length8 <= length <= 255

Request Body

application/json
  1. body
clientId*string
Length1 <= length <= 60

Response Body

Done.

application/json
  1. response
data*unknown

The action's result; its shape depends on the verb.

Example Request
curl -X POST 'https://api.usedashly.com/v1/contacts/string/actions/set-primary-account' \  -H 'Content-Type: application/json' \  -d '{  "clientId": "string"}'
Example Response
{  "data": null}
POST
/contacts/{id}/actions/merge

Folds the given contacts into this one: its empty fields are filled from theirs, everything that named them (deals, activities, calls, organisations) now names this contact, and they are deleted. Irreversible.

Does what the dashboard's mergeContactsAction does - same implementation, so the two cannot diverge.

Required scope: contacts:write.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Path Parameters

id*string

The public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.

Header Parameters

Idempotency-Key?string

A value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.

Length8 <= length <= 255

Request Body

application/json
  1. body
contactIds*array<>
Items1 <= items <= 100

Response Body

Done.

application/json
  1. response
data*unknown

The action's result; its shape depends on the verb.

Example Request
curl -X POST 'https://api.usedashly.com/v1/contacts/string/actions/merge' \  -H 'Content-Type: application/json' \  -d '{  "contactIds": [    "string"  ]}'
Example Response
{  "data": null}
GET
/contacts/{id}/actions/phone-exchanges

The person's latest phone exchanges (at most 20, newest first): calls with direction, status (answered, missed, voicemail), duration, recording link and the agent's note, and SMS with their text. Includes the unattached exchanges whose number is the person's in full. Read-only.

Reads the same data as the in-app listPhoneExchanges - same implementation. Changes nothing; also answers GET with the same fields as query parameters.

Required scope: contacts:read.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Path Parameters

id*string

The public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.

Response Body

The figures.

application/json
  1. response
data*unknown

The action's result; its shape depends on the verb.

Example Request
curl -X GET 'https://api.usedashly.com/v1/contacts/string/actions/phone-exchanges'
Example Response
{  "data": null}
POST
/contacts/{id}/actions/phone-exchanges

The person's latest phone exchanges (at most 20, newest first): calls with direction, status (answered, missed, voicemail), duration, recording link and the agent's note, and SMS with their text. Includes the unattached exchanges whose number is the person's in full. Read-only.

Reads the same data as the in-app listPhoneExchanges - same implementation. Changes nothing; also answers GET with the same fields as query parameters.

Required scope: contacts:read.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Path Parameters

id*string

The public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.

Header Parameters

Idempotency-Key?string

A value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.

Length8 <= length <= 255

Request Body

application/json
  1. body

Response Body

Done.

application/json
  1. response
data*unknown

The action's result; its shape depends on the verb.

Example Request
curl -X POST 'https://api.usedashly.com/v1/contacts/string/actions/phone-exchanges' \  -H 'Content-Type: application/json' \  -d '{}'
Example Response
{  "data": null}

Set the picture

POST
/contacts/{id}/actions/set-avatar

Stores the person's picture as a data URI (PNG, JPEG or WebP, already resized). null removes it.

Does what the dashboard's setContactAvatarAction does - same implementation, so the two cannot diverge.

Required scope: contacts:write.

Authorization

bearerAuth
headerAuthorizationBearer <token>

Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.

Path Parameters

id*string

The public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.

Header Parameters

Idempotency-Key?string

A value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.

Length8 <= length <= 255

Request Body

application/json
  1. body
avatar*|null

Response Body

Done.

application/json
  1. response
data*unknown

The action's result; its shape depends on the verb.

Example Request
curl -X POST 'https://api.usedashly.com/v1/contacts/string/actions/set-avatar' \  -H 'Content-Type: application/json' \  -d '{  "avatar": "string"}'
Example Response
{  "data": null}