Get contact
Read one contact from the platform, scoped by locationId. Set include to calls to add its call history. The record reports the latest recorded outcome. That is distinct from the current CRM do-not-call flag.
Required API key scope: contacts:read.
GET
/
api
/
contacts
/
{contactId}
cURL
curl --request GET \
--url https://api.teamfollowup.ai/api/contacts/{contactId} \
--header 'Authorization: Bearer YOUR_API_KEY'import requests
url = "https://api.teamfollowup.ai/api/contacts/{contactId}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.teamfollowup.ai/api/contacts/{contactId}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.teamfollowup.ai/api/contacts/{contactId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.teamfollowup.ai/api/contacts/{contactId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.teamfollowup.ai/api/contacts/{contactId}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.teamfollowup.ai/api/contacts/{contactId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "64f2a8c8a2b3c4d5e6f7a8b9",
"_id": "64f2a8c8a2b3c4d5e6f7a8b9",
"phoneNumber": "+14155551234",
"leadName": "Alex Morgan",
"projectName": "Acme Roofing",
"dateAdded": "2026-07-08T00:00:00.000Z",
"leadGeneratedAtInCrm": "2026-07-08T15:58:41.000Z",
"leadGeneratedAtInCrmPrecision": "time",
"leadReceivedByTfuAi": "2026-07-08T15:58:44.512Z",
"callCount": 3,
"contactId": "contact_123",
"locationId": "loc_9f7a123",
"crm": "ghl",
"leadId": null,
"kommoSubdomain": null,
"ghlWhitelabelDomain": null,
"isInternal": false,
"nextScheduledCall": {
"nextCallTime": "2026-07-09T14:30:00.000Z",
"cadenceStep": 1
},
"disposition": {
"type": "appointment",
"label": "Appointment",
"color": "green"
}
}
}{
"success": false,
"error": "ValidationFailed",
"message": "Some details need fixing. Please check the highlighted fields.",
"errors": [
{
"field": "locationId",
"code": "FieldRequired",
"message": "Please fill this in."
}
]
}{
"success": false,
"error": "Unauthorized",
"message": "Please sign in to continue."
}{
"success": false,
"error": "InsufficientScope",
"message": "This access key does not allow this action. Please ask your account admin to change its permissions.",
"requiredScope": "contacts:read"
}{
"success": false,
"error": "CONTACT_NOT_FOUND",
"message": "We could not find that contact. Please choose another one."
}{
"success": false,
"error": "ContactMatchAmbiguous",
"message": "More than one contact has that phone number. Please choose a contact from the list."
}{
"success": false,
"error": "NotFound",
"message": "We couldn't find that. It may have been moved or deleted.",
"errors": [
{
"field": "name",
"code": "FieldRequired",
"message": "Please fill this in."
}
],
"details": {},
"ref": "3f2b8c1e-7d4a-4f8e-9b6a-2c1d0e5f7a9b"
}{
"success": false,
"error": "Internal",
"message": "Something went wrong on our side. Please try again in a moment.",
"ref": "3f2b8c1e-7d4a-4f8e-9b6a-2c1d0e5f7a9b"
}Authorizations
Path Parameters
Query Parameters
⌘I
cURL
curl --request GET \
--url https://api.teamfollowup.ai/api/contacts/{contactId} \
--header 'Authorization: Bearer YOUR_API_KEY'import requests
url = "https://api.teamfollowup.ai/api/contacts/{contactId}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.teamfollowup.ai/api/contacts/{contactId}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.teamfollowup.ai/api/contacts/{contactId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.teamfollowup.ai/api/contacts/{contactId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.teamfollowup.ai/api/contacts/{contactId}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.teamfollowup.ai/api/contacts/{contactId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "64f2a8c8a2b3c4d5e6f7a8b9",
"_id": "64f2a8c8a2b3c4d5e6f7a8b9",
"phoneNumber": "+14155551234",
"leadName": "Alex Morgan",
"projectName": "Acme Roofing",
"dateAdded": "2026-07-08T00:00:00.000Z",
"leadGeneratedAtInCrm": "2026-07-08T15:58:41.000Z",
"leadGeneratedAtInCrmPrecision": "time",
"leadReceivedByTfuAi": "2026-07-08T15:58:44.512Z",
"callCount": 3,
"contactId": "contact_123",
"locationId": "loc_9f7a123",
"crm": "ghl",
"leadId": null,
"kommoSubdomain": null,
"ghlWhitelabelDomain": null,
"isInternal": false,
"nextScheduledCall": {
"nextCallTime": "2026-07-09T14:30:00.000Z",
"cadenceStep": 1
},
"disposition": {
"type": "appointment",
"label": "Appointment",
"color": "green"
}
}
}{
"success": false,
"error": "ValidationFailed",
"message": "Some details need fixing. Please check the highlighted fields.",
"errors": [
{
"field": "locationId",
"code": "FieldRequired",
"message": "Please fill this in."
}
]
}{
"success": false,
"error": "Unauthorized",
"message": "Please sign in to continue."
}{
"success": false,
"error": "InsufficientScope",
"message": "This access key does not allow this action. Please ask your account admin to change its permissions.",
"requiredScope": "contacts:read"
}{
"success": false,
"error": "CONTACT_NOT_FOUND",
"message": "We could not find that contact. Please choose another one."
}{
"success": false,
"error": "ContactMatchAmbiguous",
"message": "More than one contact has that phone number. Please choose a contact from the list."
}{
"success": false,
"error": "NotFound",
"message": "We couldn't find that. It may have been moved or deleted.",
"errors": [
{
"field": "name",
"code": "FieldRequired",
"message": "Please fill this in."
}
],
"details": {},
"ref": "3f2b8c1e-7d4a-4f8e-9b6a-2c1d0e5f7a9b"
}{
"success": false,
"error": "Internal",
"message": "Something went wrong on our side. Please try again in a moment.",
"ref": "3f2b8c1e-7d4a-4f8e-9b6a-2c1d0e5f7a9b"
}