curl --request POST \
--url https://api.nuvia.ai/v1/contacts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "João Silva",
"country_code": "55",
"phone_number": "11999998888",
"email": "joao.silva@exemplo.com.br",
"job_title": "Gerente de Vendas",
"city": "São Paulo",
"additional_attributes": {
"cpf": "12345678900"
}
}
'import requests
url = "https://api.nuvia.ai/v1/contacts"
payload = {
"name": "João Silva",
"country_code": "55",
"phone_number": "11999998888",
"email": "joao.silva@exemplo.com.br",
"job_title": "Gerente de Vendas",
"city": "São Paulo",
"additional_attributes": { "cpf": "12345678900" }
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'João Silva',
country_code: '55',
phone_number: '11999998888',
email: 'joao.silva@exemplo.com.br',
job_title: 'Gerente de Vendas',
city: 'São Paulo',
additional_attributes: {cpf: '12345678900'}
})
};
fetch('https://api.nuvia.ai/v1/contacts', 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.nuvia.ai/v1/contacts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'João Silva',
'country_code' => '55',
'phone_number' => '11999998888',
'email' => 'joao.silva@exemplo.com.br',
'job_title' => 'Gerente de Vendas',
'city' => 'São Paulo',
'additional_attributes' => [
'cpf' => '12345678900'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.nuvia.ai/v1/contacts"
payload := strings.NewReader("{\n \"name\": \"João Silva\",\n \"country_code\": \"55\",\n \"phone_number\": \"11999998888\",\n \"email\": \"joao.silva@exemplo.com.br\",\n \"job_title\": \"Gerente de Vendas\",\n \"city\": \"São Paulo\",\n \"additional_attributes\": {\n \"cpf\": \"12345678900\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.nuvia.ai/v1/contacts")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"João Silva\",\n \"country_code\": \"55\",\n \"phone_number\": \"11999998888\",\n \"email\": \"joao.silva@exemplo.com.br\",\n \"job_title\": \"Gerente de Vendas\",\n \"city\": \"São Paulo\",\n \"additional_attributes\": {\n \"cpf\": \"12345678900\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.nuvia.ai/v1/contacts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"João Silva\",\n \"country_code\": \"55\",\n \"phone_number\": \"11999998888\",\n \"email\": \"joao.silva@exemplo.com.br\",\n \"job_title\": \"Gerente de Vendas\",\n \"city\": \"São Paulo\",\n \"additional_attributes\": {\n \"cpf\": \"12345678900\"\n }\n}"
response = http.request(request)
puts response.read_body{
"name": "<string>",
"company": "<unknown>",
"_id": "<string>",
"id": "<string>",
"country_code": "<string>",
"email": "<string>",
"last_activity_at": "<unknown>",
"phone_number": "<string>",
"linkedin_identifier": "<string>",
"job_title": "<string>",
"seniority": "<string>",
"department": "<string>",
"country": "<string>",
"region": "<string>",
"city": "<string>",
"experience": "<string>",
"skills": "<string>",
"additional_attributes": {},
"business": "<string>",
"notes": [
{
"_id": "<string>",
"content": "<string>",
"user": "<string>",
"createdAt": "<unknown>",
"updatedAt": "<unknown>"
}
],
"marketing_opt_out": {},
"whatsapp_user_id": "<string>",
"whatsapp_username": "<string>",
"whatsapp_parent_user_id": "<string>",
"createdAt": "<unknown>",
"updatedAt": "<unknown>"
}Criar ou atualizar contato
Cria um contato ou, se a empresa já tem um contato com o mesmo telefone, atualiza esse contato (upsert).
- Identificação: o contato é encontrado só pelo telefone (
country_code+phone_number). E-mail e LinkedIn não são usados para encontrar contato. - Resposta: 201 tanto ao criar quanto ao encontrar um contato existente. A resposta não indica qual dos dois aconteceu.
- Contato existente: o
nameé preservado.email,linkedin_identifiereadditional_attributessão atualizados; emadditional_attributeso merge é por slug, e os slugs não enviados ficam como estão. - Campos de perfil:
job_title,seniority,department,country,region,cityeexperiencesão gravados na criação e, num contato existente, atualizados quando enviados. - Telefone: só dígitos, DDD + número, sem o DDI (o DDI vai em
country_code). Telefone inválido retorna 400. - additional_attributes:
{ "slug": valor }, com valor primitivo (string, number, boolean ou null). Slug inexistente, ou de custom field com contexto diferente de CONTACT, é ignorado em silêncio.
curl --request POST \
--url https://api.nuvia.ai/v1/contacts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "João Silva",
"country_code": "55",
"phone_number": "11999998888",
"email": "joao.silva@exemplo.com.br",
"job_title": "Gerente de Vendas",
"city": "São Paulo",
"additional_attributes": {
"cpf": "12345678900"
}
}
'import requests
url = "https://api.nuvia.ai/v1/contacts"
payload = {
"name": "João Silva",
"country_code": "55",
"phone_number": "11999998888",
"email": "joao.silva@exemplo.com.br",
"job_title": "Gerente de Vendas",
"city": "São Paulo",
"additional_attributes": { "cpf": "12345678900" }
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'João Silva',
country_code: '55',
phone_number: '11999998888',
email: 'joao.silva@exemplo.com.br',
job_title: 'Gerente de Vendas',
city: 'São Paulo',
additional_attributes: {cpf: '12345678900'}
})
};
fetch('https://api.nuvia.ai/v1/contacts', 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.nuvia.ai/v1/contacts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'João Silva',
'country_code' => '55',
'phone_number' => '11999998888',
'email' => 'joao.silva@exemplo.com.br',
'job_title' => 'Gerente de Vendas',
'city' => 'São Paulo',
'additional_attributes' => [
'cpf' => '12345678900'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.nuvia.ai/v1/contacts"
payload := strings.NewReader("{\n \"name\": \"João Silva\",\n \"country_code\": \"55\",\n \"phone_number\": \"11999998888\",\n \"email\": \"joao.silva@exemplo.com.br\",\n \"job_title\": \"Gerente de Vendas\",\n \"city\": \"São Paulo\",\n \"additional_attributes\": {\n \"cpf\": \"12345678900\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.nuvia.ai/v1/contacts")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"João Silva\",\n \"country_code\": \"55\",\n \"phone_number\": \"11999998888\",\n \"email\": \"joao.silva@exemplo.com.br\",\n \"job_title\": \"Gerente de Vendas\",\n \"city\": \"São Paulo\",\n \"additional_attributes\": {\n \"cpf\": \"12345678900\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.nuvia.ai/v1/contacts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"João Silva\",\n \"country_code\": \"55\",\n \"phone_number\": \"11999998888\",\n \"email\": \"joao.silva@exemplo.com.br\",\n \"job_title\": \"Gerente de Vendas\",\n \"city\": \"São Paulo\",\n \"additional_attributes\": {\n \"cpf\": \"12345678900\"\n }\n}"
response = http.request(request)
puts response.read_body{
"name": "<string>",
"company": "<unknown>",
"_id": "<string>",
"id": "<string>",
"country_code": "<string>",
"email": "<string>",
"last_activity_at": "<unknown>",
"phone_number": "<string>",
"linkedin_identifier": "<string>",
"job_title": "<string>",
"seniority": "<string>",
"department": "<string>",
"country": "<string>",
"region": "<string>",
"city": "<string>",
"experience": "<string>",
"skills": "<string>",
"additional_attributes": {},
"business": "<string>",
"notes": [
{
"_id": "<string>",
"content": "<string>",
"user": "<string>",
"createdAt": "<unknown>",
"updatedAt": "<unknown>"
}
],
"marketing_opt_out": {},
"whatsapp_user_id": "<string>",
"whatsapp_username": "<string>",
"whatsapp_parent_user_id": "<string>",
"createdAt": "<unknown>",
"updatedAt": "<unknown>"
}Autorizações
Token JWT de autenticação
Cabeçalhos
Identificador da empresa-alvo. Obrigatório apenas para API Keys globais (type=global). Ignorado para API Keys de empresa e usuários humanos.
Corpo
Nome completo do contato. Campo obrigatório. Se já existe contato com o mesmo telefone, o nome dele é preservado.
1Código DDI do país (1-3 dígitos). Exemplos: 55 (Brasil), 1 (EUA), 351 (Portugal). Junto com phone_number, identifica o contato: se já existe contato da empresa com esse telefone, ele é atualizado em vez de criado.
1 - 3^\d{1,3}$Número de telefone sem formatação, apenas dígitos (DDD + número, sem o DDI). Exemplo: 11999998888. Telefone que não forma um número válido com o country_code é recusado com 400.
1^\d+$Endereço de e-mail do contato. Campo opcional. Não é usado para encontrar o contato; num contato existente, substitui o e-mail atual.
Identificador do LinkedIn do contato (nome do perfil). Exemplo: joao-silva-123. Não é usado para encontrar o contato; num contato existente, substitui o valor atual.
Cargo do contato. Exemplo: Gerente de Vendas. Gravado na criação; num contato existente, atualizado quando enviado.
Nível de senioridade do contato. Exemplo: Senior, Junior, Pleno. Gravado na criação; num contato existente, atualizado quando enviado.
Departamento do contato. Exemplo: Comercial, TI, Marketing. Gravado na criação; num contato existente, atualizado quando enviado.
País do contato. Exemplo: Brasil. Gravado na criação; num contato existente, atualizado quando enviado.
Estado ou região do contato. Exemplo: São Paulo. Gravado na criação; num contato existente, atualizado quando enviado.
Cidade do contato. Exemplo: São Paulo. Gravado na criação; num contato existente, atualizado quando enviado.
Experiência profissional do contato. Gravado na criação; num contato existente, atualizado quando enviado.
Campos personalizados do contato. Formato: { "slug_do_campo": valor }. Os slugs devem corresponder a custom fields cadastrados com contexto CONTACT. Slugs inválidos ou inexistentes são ignorados silenciosamente. Os valores devem ser primitivos (string, number, boolean ou null). Num contato existente, só os slugs enviados são atualizados (merge); os demais ficam como estão. Exemplo: { "cpf": "12345678900", "data_nascimento": "1990-01-15", "valor_total": 1500.50 }
Show child attributes
Show child attributes
Resposta
Contato criado, ou contato existente com o mesmo telefone atualizado
Nome do contato
Empresa do contato
ID do contato
ID do contato (mesmo valor de _id)
Código do país do número. Ausente junto com o telefone quando o contato só tem identificador do WhatsApp.
E-mail do contato
Data da última atividade do contato
Número de telefone do contato. Ausente quando o contato só tem identificador do WhatsApp.
Identificador do perfil do LinkedIn
Cargo do contato
Nível de senioridade do contato
Departamento do contato
País do contato
Estado ou região do contato
Cidade do contato
Experiência profissional do contato
Habilidades do contato
Valores dos campos personalizados do contato, por slug. Gravado via additional_attributes, o valor vem no envelope { id, value, type, updatedAt }. Gravado via custom_fields (PUT), vem cru: o option_id (select), a lista de option_id (multi_select) ou o texto (text).
Show child attributes
Show child attributes
ID do Business ao qual o contato pertence
Notas registradas no contato
Show child attributes
Show child attributes
Opt-out de marketing por meio de comunicação (whatsapp, email, linkedin). Ausente ou vazio quando o contato não pediu para sair de nenhum meio.
Show child attributes
Show child attributes
Identificador do contato no WhatsApp (BSUID), atribuído pela Meta. String opaca.
@username do contato no WhatsApp, como a Meta envia
parent_user_id do contato no WhatsApp, como a Meta envia
Data de criação do contato
Data de atualização do contato