Contacts API Routes
GET /api/contacts
Seção intitulada “GET /api/contacts”Descrição: Lista contatos da conta com suporte a paginação offset-based, cursor-based, busca textual, e filtros avancados (3-level segment filters). Auth: Required
Request:
- Query params:
- Páginação offset (quando
pagepresente):page(number, default: 1)limit(number, default: 20, max: 100)sort(string, optional)order(“asc” | “desc”, default: “desc”)
- Páginação cursor (quando
cursorpresente ou nenhumpage):cursor(string, optional)limit(number, default: 20, max: 100)
- Busca:
search(string) - Busca textual (nome, telefone, email) - Filtros (parseados via
parseFiltersFromParams):filter_field_0,filter_operator_0,filter_value_0(até 5 filtros)- Campos suportados:
name,phone,email,created_at,tag,rfm_segment - Operadores:
equals,not_equals,contains,not_contains,starts_with,is_empty,is_not_empty,gt,lt
- Páginação offset (quando
Response (modo cursor):
- 200:
{ data: Contact[], nextCursor: string | null, hasMore: boolean }
Response (modo offset):
- 200:
{ data: Contact[], total: number, page: number, limit: number, totalPages: number }
Notas:
- Máximo 5 filtros. Retorna 400 se exceder.
- Filtros de
tagerfm_segmentfazem sub-queries emcontact_tags/tagsecontact_rfm_scores. - Valores de filtro são sanitizados (caracteres especiais SQL escapados).
- Contatos com
deleted_atnão-nulo são excluidos automaticamente.
POST /api/contacts
Seção intitulada “POST /api/contacts”Descrição: Cria um novo contato. Verifica plano ativo e limites antes de criar. Auth: Required
Request:
- Body (contactSchema):
{"name": "string (1-200 chars, obrigatório)","phone": "string (10-20 chars, obrigatório)","email": "string email (opcional)","metadata": { "key": "value" }}
Response:
- 201:
Contact - 422: Erro de validação
Notas:
- Verifica
requireActivePlanerequirePlanLimit(limite de contatos do plano). - Side effects: emite evento
METRIC_CONTACT_CREATED, dispara triggernew_contactse contato tem telefone.
GET /api/contacts/[id]
Seção intitulada “GET /api/contacts/[id]”Descrição: Retorna um contato específico pelo ID. Auth: Required
Response:
- 200:
Contact - 404: Contato não encontrado
PUT /api/contacts/[id]
Seção intitulada “PUT /api/contacts/[id]”Descrição: Atualiza um contato existente. Detecta campos alterados e dispara triggers/eventos. Auth: Required
Request:
- Body (contactUpdateSchema = contactSchema.partial()): Qualquer campo, todos opcionais
Response:
- 200:
Contact(atualizado) - 404: Contato não encontrado
Notas:
- Rastreia mudancas em
name,email,phone. - Para cada campo alterado: dispara trigger
contact_updatedcom old_value/new_value. - Emite evento
METRIC_CONTACT_UPDATEDcom detalhes das mudancas.
DELETE /api/contacts/[id]
Seção intitulada “DELETE /api/contacts/[id]”Descrição: Soft-delete de um contato (seta deleted_at).
Auth: Required
Audit: delete / contact
Response:
- 204: No content
POST /api/contacts/bulk-action
Seção intitulada “POST /api/contacts/bulk-action”Descrição: Executa ações em massa sobre contatos selecionados. Suporta add_tag, remove_tag, delete e export.
Auth: Required
Rate Limit: Custom - 10 req/60s - chave: bulk-action:{ip}
Request:
- Body (bulkActionSchema):
{"action": "add_tag | remove_tag | delete | export","contact_ids": ["uuid[]", "1-1000 itens, obrigatório"],"tag_id": "uuid (obrigatório para add_tag/remove_tag)"}
Response (add_tag / remove_tag / delete):
- 200:
{ affected: number, action: string }
Response (export):
- 200:
{ affected: 10, action: "export", contacts: [...] }
Notas:
- Verifica ownership dos contatos antes de agir.
add_tag: upsert emcontact_tags, dispara triggertag_addedpara cada contato.remove_tag: delete decontact_tags, dispara triggertag_removedpara cada contato.delete: soft-delete (setadeleted_at).
POST /api/contacts/import
Seção intitulada “POST /api/contacts/import”Descrição: Importa contatos em massa via arquivo CSV. Valida formato, telefone (E.164), email, e faz upsert por account_id,phone.
Auth: Required
Rate Limit: Custom - 5 req/60s - chave: import:{accountId}
Audit: create / contacts_import
Request:
- Content-Type:
multipart/form-data - Body:
file(File, obrigatório) - Arquivo CSV (max 5MB, max 10.000 linhas)
CSV esperado:
name,phone,emailJoao Silva,+5511999991234,joao@email.comResponse:
- 200:
{"imported": 95,"skipped": 3,"total": 100,"errors": [{ "line": 5, "reason": "Telefone inválido: \"abc\"" }]}
Notas:
- Normalização de telefone: aceita E.164, formato brasileiro, ou apenas digitos.
- Upsert com
onConflict: "account_id,phone"eignoreDuplicates: true. - Processado em batches de 100. Retorna até 100 erros.
- Verifica
requireActivePlanerequirePlanLimitantes do import.
GET /api/contacts/import/template
Seção intitulada “GET /api/contacts/import/template”Descrição: Retorna um arquivo CSV modelo para importação de contatos. Auth: Public (sem autenticação)
Response:
- 200: Arquivo CSV (
text/csv; charset=utf-8) com Content-Dispositionattachment; filename="contatos_modelo.csv"
GET /api/contacts/[id]/conversations
Seção intitulada “GET /api/contacts/[id]/conversations”Descrição: Lista as conversas de um contato específico, enriquecidas com a última mensagem de cada conversa. Auth: Required
Response:
- 200: Array de conversas com
last_message_contentelast_message_direction - 404: Contato não encontrado
Notas: Limite de 20 conversas, ordenadas por last_message_at desc.
GET /api/contacts/[id]/activity
Seção intitulada “GET /api/contacts/[id]/activity”Descrição: Retorna timeline de atividades do contato, mesclando mensagens e logs de auditoria em ordem cronológica. Auth: Required
Response:
- 200: Array de atividades com tipo, título, descrição e metadata
- 404: Contato não encontrado
Notas: Combina até 30 mensagens + até 20 audit_logs. Ordena por created_at desc, limita a 50 itens.
GET /api/contacts/[id]/rfm
Seção intitulada “GET /api/contacts/[id]/rfm”Descrição: Retorna o score RFM (Recency, Frequency, Monetary) de um contato. Auth: Required
Response:
- 200:
ContactRfmScore | null
GET /api/contacts/[id]/events
Seção intitulada “GET /api/contacts/[id]/events”Descrição: Lista eventos (métricas) de um contato com paginação cursor-based. Auth: Required
Request:
- Query params:
cursor(string, optional),limit(number, default: 20)
Response:
- 200:
{ items: Event[], nextCursor: string | null } - 404: Contato não encontrado
GET /api/contacts/[id]/events/summary
Seção intitulada “GET /api/contacts/[id]/events/summary”Descrição: Retorna resumo agregado dos eventos/métricas de um contato, incluindo contagem de pedidos e receita. Auth: Required
Response:
- 200:
{ metrics: MetricSummary[], orders: { count, revenue } } - 404: Contato não encontrado
GET /api/contacts/[id]/tags
Seção intitulada “GET /api/contacts/[id]/tags”Descrição: Lista todas as tags atribuidas a um contato. Auth: Required
Response:
- 200: Array de tags
[{ id, name, color }]
POST /api/contacts/[id]/tags
Seção intitulada “POST /api/contacts/[id]/tags”Descrição: Adiciona uma tag a um contato. Auth: Required
Request:
- Body:
{ "tag_id": "uuid" }
Response:
- 201:
{ contact_id, tag_id, tag_name } - 404: Contato ou tag não encontrada
Notas: Upsert em contact_tags (ignora se já existe). Dispara trigger tag_added.
DELETE /api/contacts/[id]/tags
Seção intitulada “DELETE /api/contacts/[id]/tags”Descrição: Remove uma tag de um contato. Auth: Required
Request:
- Body:
{ "tag_id": "uuid" }
Response:
- 200:
{ contact_id, tag_id, tag_name } - 404: Contato ou tag não encontrada
Notas: Dispara trigger tag_removed. Verifica ownership antes de remover.