Ndoto Docs

Contacts

Create, search, update, and manage contact records

Contacts

Contacts represent the people who interact with your team. Every conversation is linked to a contact.

Base path: /api/v1/accounts/:account_id/contacts


List contacts

Returns a paginated list of all contacts.

GET /api/v1/accounts/:account_id/contacts

Query parameters

ParameterTypeRequiredDescription
pagenumberNoPage number. Default: 1 (15 per page)
sortstringNoSort by: name, email, phone_number, last_activity_at, created_at
include_contact_inboxesbooleanNoInclude inbox associations in the response

Response

{
  "payload": [
    {
      "id": 10,
      "name": "Jane Doe",
      "email": "[email protected]",
      "phone_number": "+1234567890",
      "identifier": "user_123",
      "blocked": false,
      "thumbnail": "https://...",
      "last_activity_at": 1712001000,
      "created_at": 1711000000,
      "custom_attributes": {}
    }
  ],
  "meta": {
    "count": 200,
    "current_page": 1
  }
}
const response = await fetch(
  'https://app.usendoto.com/api/v1/accounts/1/contacts?page=1',
  {
    headers: { 'api_access_token': 'YOUR_TOKEN' },
  }
);
const data = await response.json();
console.log(data.payload);
import requests

response = requests.get(
    'https://app.usendoto.com/api/v1/accounts/1/contacts',
    headers={'api_access_token': 'YOUR_TOKEN'},
    params={'page': 1},
)
print(response.json())
<?php
$ch = curl_init('https://app.usendoto.com/api/v1/accounts/1/contacts?page=1');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['api_access_token: YOUR_TOKEN'],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
import 'package:http/http.dart' as http;
import 'dart:convert';

final response = await http.get(
  Uri.parse('https://app.usendoto.com/api/v1/accounts/1/contacts?page=1'),
  headers: {'api_access_token': 'YOUR_TOKEN'},
);
print(jsonDecode(response.body));
require 'net/http'
require 'json'

uri = URI('https://app.usendoto.com/api/v1/accounts/1/contacts')
uri.query = URI.encode_www_form(page: 1)

req = Net::HTTP::Get.new(uri)
req['api_access_token'] = 'YOUR_TOKEN'

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts JSON.parse(res.body)

Search contacts

Searches contacts by name, email, or phone number.

GET /api/v1/accounts/:account_id/contacts/search

Query parameters

ParameterTypeRequiredDescription
qstringYesSearch query
pagenumberNoPage number
include_contactsbooleanNoInclude full contact objects (default true)
const response = await fetch(
  'https://app.usendoto.com/api/v1/accounts/1/contacts/search?q=jane',
  {
    headers: { 'api_access_token': 'YOUR_TOKEN' },
  }
);
const data = await response.json();
console.log(data.payload);
response = requests.get(
    'https://app.usendoto.com/api/v1/accounts/1/contacts/search',
    headers={'api_access_token': 'YOUR_TOKEN'},
    params={'q': 'jane'},
)
print(response.json())
<?php
$ch = curl_init('https://app.usendoto.com/api/v1/accounts/1/contacts/search?q=jane');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['api_access_token: YOUR_TOKEN'],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
final uri = Uri.parse('https://app.usendoto.com/api/v1/accounts/1/contacts/search')
    .replace(queryParameters: {'q': 'jane'});

final response = await http.get(
  uri,
  headers: {'api_access_token': 'YOUR_TOKEN'},
);
print(jsonDecode(response.body));
uri = URI('https://app.usendoto.com/api/v1/accounts/1/contacts/search')
uri.query = URI.encode_www_form(q: 'jane')

req = Net::HTTP::Get.new(uri)
req['api_access_token'] = 'YOUR_TOKEN'

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts JSON.parse(res.body)

Get a contact

Returns a single contact by ID.

GET /api/v1/accounts/:account_id/contacts/:id
const response = await fetch(
  'https://app.usendoto.com/api/v1/accounts/1/contacts/10',
  {
    headers: { 'api_access_token': 'YOUR_TOKEN' },
  }
);
const contact = await response.json();
console.log(contact);
response = requests.get(
    'https://app.usendoto.com/api/v1/accounts/1/contacts/10',
    headers={'api_access_token': 'YOUR_TOKEN'},
)
print(response.json())
<?php
$ch = curl_init('https://app.usendoto.com/api/v1/accounts/1/contacts/10');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['api_access_token: YOUR_TOKEN'],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
final response = await http.get(
  Uri.parse('https://app.usendoto.com/api/v1/accounts/1/contacts/10'),
  headers: {'api_access_token': 'YOUR_TOKEN'},
);
print(jsonDecode(response.body));
uri = URI('https://app.usendoto.com/api/v1/accounts/1/contacts/10')
req = Net::HTTP::Get.new(uri)
req['api_access_token'] = 'YOUR_TOKEN'

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts JSON.parse(res.body)

Create a contact

Creates a new contact.

POST /api/v1/accounts/:account_id/contacts

Body parameters

ParameterTypeRequiredDescription
namestringYesFull name of the contact
emailstringNoEmail address
phone_numberstringNoPhone number in E.164 format (e.g. +1234567890)
identifierstringNoYour own unique identifier for this contact
blockedbooleanNoWhether the contact is blocked
custom_attributesobjectNoKey-value pairs of custom attribute values
additional_attributesobjectNoExtra metadata
const response = await fetch(
  'https://app.usendoto.com/api/v1/accounts/1/contacts',
  {
    method: 'POST',
    headers: {
      'api_access_token': 'YOUR_TOKEN',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: 'Jane Doe',
      email: '[email protected]',
      phone_number: '+1234567890',
      identifier: 'user_123',
      custom_attributes: { plan: 'premium' },
    }),
  }
);
const contact = await response.json();
console.log(contact);
response = requests.post(
    'https://app.usendoto.com/api/v1/accounts/1/contacts',
    headers={'api_access_token': 'YOUR_TOKEN'},
    json={
        'name': 'Jane Doe',
        'email': '[email protected]',
        'phone_number': '+1234567890',
        'identifier': 'user_123',
        'custom_attributes': {'plan': 'premium'},
    },
)
print(response.json())
<?php
$payload = json_encode([
    'name'              => 'Jane Doe',
    'email'             => '[email protected]',
    'phone_number'      => '+1234567890',
    'identifier'        => 'user_123',
    'custom_attributes' => ['plan' => 'premium'],
]);

$ch = curl_init('https://app.usendoto.com/api/v1/accounts/1/contacts');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $payload,
    CURLOPT_HTTPHEADER     => [
        'api_access_token: YOUR_TOKEN',
        'Content-Type: application/json',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
final response = await http.post(
  Uri.parse('https://app.usendoto.com/api/v1/accounts/1/contacts'),
  headers: {
    'api_access_token': 'YOUR_TOKEN',
    'Content-Type': 'application/json',
  },
  body: jsonEncode({
    'name': 'Jane Doe',
    'email': '[email protected]',
    'phone_number': '+1234567890',
    'identifier': 'user_123',
    'custom_attributes': {'plan': 'premium'},
  }),
);
print(jsonDecode(response.body));
uri = URI('https://app.usendoto.com/api/v1/accounts/1/contacts')
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
req['api_access_token'] = 'YOUR_TOKEN'
req.body = JSON.dump(
  name: 'Jane Doe',
  email: '[email protected]',
  phone_number: '+1234567890',
  identifier: 'user_123',
  custom_attributes: { plan: 'premium' }
)

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts JSON.parse(res.body)

Update a contact

Updates an existing contact's details.

PATCH /api/v1/accounts/:account_id/contacts/:id

Body parameters

Same as create — include only the fields you want to update.

const response = await fetch(
  'https://app.usendoto.com/api/v1/accounts/1/contacts/10',
  {
    method: 'PATCH',
    headers: {
      'api_access_token': 'YOUR_TOKEN',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: 'Jane Smith',
      custom_attributes: { plan: 'enterprise' },
    }),
  }
);
const updated = await response.json();
console.log(updated);
response = requests.patch(
    'https://app.usendoto.com/api/v1/accounts/1/contacts/10',
    headers={'api_access_token': 'YOUR_TOKEN'},
    json={
        'name': 'Jane Smith',
        'custom_attributes': {'plan': 'enterprise'},
    },
)
print(response.json())
<?php
$ch = curl_init('https://app.usendoto.com/api/v1/accounts/1/contacts/10');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_POSTFIELDS     => json_encode([
        'name'              => 'Jane Smith',
        'custom_attributes' => ['plan' => 'enterprise'],
    ]),
    CURLOPT_HTTPHEADER => [
        'api_access_token: YOUR_TOKEN',
        'Content-Type: application/json',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
final response = await http.patch(
  Uri.parse('https://app.usendoto.com/api/v1/accounts/1/contacts/10'),
  headers: {
    'api_access_token': 'YOUR_TOKEN',
    'Content-Type': 'application/json',
  },
  body: jsonEncode({
    'name': 'Jane Smith',
    'custom_attributes': {'plan': 'enterprise'},
  }),
);
print(jsonDecode(response.body));
uri = URI('https://app.usendoto.com/api/v1/accounts/1/contacts/10')
req = Net::HTTP::Patch.new(uri, 'Content-Type' => 'application/json')
req['api_access_token'] = 'YOUR_TOKEN'
req.body = JSON.dump(
  name: 'Jane Smith',
  custom_attributes: { plan: 'enterprise' }
)

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts JSON.parse(res.body)

Delete a contact

Permanently deletes a contact and all their associated data.

DELETE /api/v1/accounts/:account_id/contacts/:id
const response = await fetch(
  'https://app.usendoto.com/api/v1/accounts/1/contacts/10',
  {
    method: 'DELETE',
    headers: { 'api_access_token': 'YOUR_TOKEN' },
  }
);
console.log(response.status); // 200
response = requests.delete(
    'https://app.usendoto.com/api/v1/accounts/1/contacts/10',
    headers={'api_access_token': 'YOUR_TOKEN'},
)
print(response.status_code)  # 200
<?php
$ch = curl_init('https://app.usendoto.com/api/v1/accounts/1/contacts/10');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['api_access_token: YOUR_TOKEN'],
]);
curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
final response = await http.delete(
  Uri.parse('https://app.usendoto.com/api/v1/accounts/1/contacts/10'),
  headers: {'api_access_token': 'YOUR_TOKEN'},
);
print(response.statusCode); // 200
uri = URI('https://app.usendoto.com/api/v1/accounts/1/contacts/10')
req = Net::HTTP::Delete.new(uri)
req['api_access_token'] = 'YOUR_TOKEN'

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code # 200

Get contact conversations

Returns all conversations for a specific contact.

GET /api/v1/accounts/:account_id/contacts/:id/conversations
const response = await fetch(
  'https://app.usendoto.com/api/v1/accounts/1/contacts/10/conversations',
  {
    headers: { 'api_access_token': 'YOUR_TOKEN' },
  }
);
const data = await response.json();
console.log(data.payload);
response = requests.get(
    'https://app.usendoto.com/api/v1/accounts/1/contacts/10/conversations',
    headers={'api_access_token': 'YOUR_TOKEN'},
)
print(response.json())
<?php
$ch = curl_init('https://app.usendoto.com/api/v1/accounts/1/contacts/10/conversations');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['api_access_token: YOUR_TOKEN'],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
final response = await http.get(
  Uri.parse('https://app.usendoto.com/api/v1/accounts/1/contacts/10/conversations'),
  headers: {'api_access_token': 'YOUR_TOKEN'},
);
print(jsonDecode(response.body));
uri = URI('https://app.usendoto.com/api/v1/accounts/1/contacts/10/conversations')
req = Net::HTTP::Get.new(uri)
req['api_access_token'] = 'YOUR_TOKEN'

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts JSON.parse(res.body)

Add a note to a contact

Adds an internal note to a contact's profile.

POST /api/v1/accounts/:account_id/contacts/:id/notes

Body parameters

ParameterTypeRequiredDescription
contentstringYesThe note text
const response = await fetch(
  'https://app.usendoto.com/api/v1/accounts/1/contacts/10/notes',
  {
    method: 'POST',
    headers: {
      'api_access_token': 'YOUR_TOKEN',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ content: 'Customer is on enterprise plan, handle with priority.' }),
  }
);
const note = await response.json();
console.log(note);
response = requests.post(
    'https://app.usendoto.com/api/v1/accounts/1/contacts/10/notes',
    headers={'api_access_token': 'YOUR_TOKEN'},
    json={'content': 'Customer is on enterprise plan, handle with priority.'},
)
print(response.json())
<?php
$ch = curl_init('https://app.usendoto.com/api/v1/accounts/1/contacts/10/notes');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => json_encode(['content' => 'Customer is on enterprise plan, handle with priority.']),
    CURLOPT_HTTPHEADER     => [
        'api_access_token: YOUR_TOKEN',
        'Content-Type: application/json',
    ],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
final response = await http.post(
  Uri.parse('https://app.usendoto.com/api/v1/accounts/1/contacts/10/notes'),
  headers: {
    'api_access_token': 'YOUR_TOKEN',
    'Content-Type': 'application/json',
  },
  body: jsonEncode({'content': 'Customer is on enterprise plan, handle with priority.'}),
);
print(jsonDecode(response.body));
uri = URI('https://app.usendoto.com/api/v1/accounts/1/contacts/10/notes')
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
req['api_access_token'] = 'YOUR_TOKEN'
req.body = JSON.dump(content: 'Customer is on enterprise plan, handle with priority.')

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts JSON.parse(res.body)

On this page