Documentação
API Pública de Onboarding¶
Guia completo para integrar o onboarding na sua aplicação usando a API REST pública.
Visão Geral¶
A API pública permite que você:
- Obtenha a estrutura do fluxo
- Inicie onboarding para clientes
- Acompanhe progresso em tempo real
- Colete dados dos usuários
- Sincronize status via webhooks
Base URL: https://api.atendeaqui.com/api/onboarding
Autenticação:
- Via URL: /{public_key}/structure/
- Via Header: X-Onboarding-Key: {public_key}
- Via Bearer Token (widgets): Authorization: Bearer <widget_token>
Segurança¶
⚠️ IMPORTANTE: A
public_keyé uma chave pública que fica exposta no frontend do seu cliente.
Para proteger seu endpoint, configure origens permitidas no dashboard:
// Campo allowed_origins no flow
["https://app.seucliente.com", "https://www.seucliente.com"]
Como funciona:
- Se allowed_origins estiver vazio → aceita qualquer origem
- Se configurado → valida o header Origin da requisição
- Requisições server-to-server (sem Origin) → sempre permitidas
Pré-requisitos¶
Antes de começar, você precisa:
- Ter um fluxo criado no dashboard
- Obter a Public Key do fluxo
- Configurar allowed_origins (recomendado para produção)
- (Opcional) Ter um cliente cadastrado e seu
client_id
Endpoints Disponíveis¶
1. Obter Estrutura do Fluxo¶
Retorna a estrutura completa do fluxo com steps traduzidos.
Request:
GET /{public_key}/structure?language=pt-BR
X-Onboarding-Key: {public_key}
Query Parameters:
- language (opcional): Idioma desejado (pt-BR, en-US, etc)
Response:
{
"id": 123,
"name": "Onboarding de Clientes",
"slug": "onboarding-clientes",
"flow_type": "LINEAR",
"available_languages": ["pt-BR", "en-US"],
"step_count": 5,
"steps": [
{
"step_key": "welcome",
"language": "pt-BR",
"title": "Bem-vindo!",
"description": "Vamos começar sua jornada",
"content": "# Olá!\n\nEstamos felizes...",
"content_html": "<h1>Olá!</h1><p>Estamos felizes...</p>",
"order": 1,
"is_required": true,
"can_skip": false,
"step_type": "INFO",
"step_config": {},
"is_first": true,
"is_last": false
},
{
"step_key": "configure-profile",
"title": "Configure seu Perfil",
"order": 2,
"is_required": true,
"can_skip": false,
"step_type": "FORM",
"step_config": {
"form_fields": [...]
}
}
]
}
Quando usar:
- Na primeira vez que o usuário acessa
- Para cachear a estrutura no frontend
- Quando o idioma do usuário muda
2. Iniciar Onboarding¶
Cria ou recupera o progresso de um usuário no fluxo.
Request:
POST /{public_key}/start
X-Onboarding-Key: {public_key}
Content-Type: application/json
{
"external_user_id": "user_123456",
"external_user_email": "usuario@example.com",
"client_id": "cliente_uuid_aqui",
"metadata": {
"preferred_language": "pt-BR",
"name": "João Silva",
"company": "Empresa XYZ"
}
}
Body Parameters:
- external_user_id (obrigatório): ID do usuário na sua aplicação
- external_user_email (opcional): E-mail do usuário
- client_id (opcional): UUID do ClientMembership para vincular
- client_team_membership_id (opcional): ID do membro da equipe
- metadata (opcional): Dados adicionais do usuário
Response:
{
"external_user_id": "user_123456",
"external_user_email": "usuario@example.com",
"flow_name": "Onboarding de Clientes",
"status": "IN_PROGRESS",
"current_step_key": "welcome",
"current_step_title": "Bem-vindo!",
"completion_percentage": 0,
"steps_completed": [],
"steps_skipped": [],
"client_id": "cliente_uuid_aqui",
"client_team_membership_id": null,
"started_at": "2026-01-12T10:30:00Z",
"completed_at": null,
"last_activity_at": "2026-01-12T10:30:00Z"
}
Status possíveis:
- NOT_STARTED: Ainda não iniciou
- IN_PROGRESS: Em andamento
- COMPLETED: Concluído
- SKIPPED: Pulado pelo usuário
- ABANDONED: Abandonado (sem atividade)
Response Codes:
- 201 Created: Progresso criado pela primeira vez
- 200 OK: Progresso já existia, retornado
3. Consultar Progresso¶
Obtém o status atual do onboarding de um usuário.
Request:
GET /{public_key}/progress/{external_user_id}
X-Onboarding-Key: {public_key}
Response:
{
"external_user_id": "user_123456",
"flow_name": "Onboarding de Clientes",
"status": "IN_PROGRESS",
"current_step_key": "configure-profile",
"current_step_title": "Configure seu Perfil",
"completion_percentage": 40,
"steps_completed": ["welcome", "accept-terms"],
"steps_skipped": [],
"started_at": "2026-01-12T10:30:00Z",
"last_activity_at": "2026-01-12T10:45:00Z"
}
Quando usar:
- Ao carregar página de onboarding
- Para sincronizar estado
- Para exibir progresso visual
4. Completar Etapa¶
Marca uma etapa como concluída e avança para a próxima.
Request:
POST /{public_key}/progress/{external_user_id}/complete-step
X-Onboarding-Key: {public_key}
Content-Type: application/json
{
"step_key": "configure-profile",
"step_data": {
"company_name": "Empresa XYZ",
"employees": "11-50",
"industry": "Tecnologia"
}
}
Body Parameters:
- step_key (obrigatório): Chave do step a completar
- step_data (opcional): Dados coletados nesta etapa
Response:
{
"external_user_id": "user_123456",
"status": "IN_PROGRESS",
"current_step_key": "connect-integrations",
"current_step_title": "Conectar Integrações",
"completion_percentage": 60,
"steps_completed": ["welcome", "accept-terms", "configure-profile"],
"steps_skipped": [],
"last_activity_at": "2026-01-12T10:50:00Z"
}
Comportamento:
- Step é adicionado a steps_completed
- current_step_key avança para o próximo
- step_data é armazenado em progress.step_data[step_key]
- Se todos os obrigatórios forem completos, status vira COMPLETED
5. Pular Etapa¶
Pula uma etapa (se permitido).
Request:
POST /{public_key}/progress/{external_user_id}/skip-step
X-Onboarding-Key: {public_key}
Content-Type: application/json
{
"step_key": "optional-survey"
}
Response:
{
"external_user_id": "user_123456",
"status": "IN_PROGRESS",
"current_step_key": "next-step",
"steps_completed": ["welcome", "configure-profile"],
"steps_skipped": ["optional-survey"]
}
Validações:
- Step deve ter can_skip: true
- Retorna erro 400 se não pode ser pulado
6. Completar Fluxo¶
Marca o fluxo como completo manualmente.
Request:
POST /{public_key}/progress/{external_user_id}/complete
X-Onboarding-Key: {public_key}
Response:
{
"external_user_id": "user_123456",
"status": "COMPLETED",
"current_step_key": null,
"completion_percentage": 100,
"completed_at": "2026-01-12T11:00:00Z"
}
Quando usar:
- Quando usuário clica em "Finalizar"
- Para forçar conclusão após validação externa
- Para marcar como completo fora do fluxo normal
7. Atualizar Metadata do Usuário¶
Atualiza os metadados do usuário (faz merge com dados existentes).
Request:
PATCH /{public_key}/progress/{external_user_id}/metadata
X-Onboarding-Key: {public_key}
Content-Type: application/json
{
"metadata": {
"company": "Nova Empresa",
"plan": "pro",
"preferred_language": "en-US"
}
}
Response: Retorna o progresso completo atualizado.
Comportamento:
- Faz merge (update) com metadata existente
- Campos novos são adicionados, campos existentes são atualizados
- Campos não enviados permanecem inalterados
8. Completar Múltiplas Etapas (Batch)¶
Completa vários steps em uma única requisição. Útil para integrações server-to-server.
Request:
POST /{public_key}/progress/{external_user_id}/complete-steps
X-Onboarding-Key: {public_key}
Content-Type: application/json
{
"steps": [
{"step_key": "welcome", "step_data": {}},
{"step_key": "config", "step_data": {"api_key": "xxx"}}
]
}
Response: Retorna o progresso final após completar todos os steps.
Validações:
- Máximo de 50 steps por requisição
- Retorna erro 400 se algum step_key não existir
SDK Python¶
Para integrações server-to-server, recomendamos o uso do SDK Python oficial:
pip install atendeaqui
from atendeaqui import AtendeAquiClient
client = AtendeAquiClient(
api_key="sua-public-key",
base_url="https://seudominio.atendeaqui.com.br",
)
# Iniciar onboarding
progress = client.onboarding.start_flow(user_id="user-123", email="user@example.com")
# Completar step
progress = client.onboarding.complete_step(user_id="user-123", step_key="welcome")
# Consultar progresso
progress = client.onboarding.get_progress(user_id="user-123")
print(f"Progresso: {progress.completion_percentage}%")
Veja a documentação completa do SDK no repositório atendeaqui-python.
Formato de Erros¶
As respostas de erro seguem um formato padronizado:
{
"error": {
"code": "STEP_NOT_FOUND",
"message": "Step 'invalid-key' não existe neste flow"
}
}
Códigos de erro:
| Código | HTTP | Descrição |
|---|---|---|
FLOW_NOT_FOUND |
404 | Flow não encontrado ou inativo |
PROGRESS_NOT_FOUND |
404 | Progresso do usuário não encontrado |
STEP_NOT_FOUND |
400 | Step não existe no flow |
STEP_NOT_SKIPPABLE |
400 | Step não pode ser pulado |
ORIGIN_NOT_ALLOWED |
400 | Origem (CORS) não permitida |
VALIDATION_ERROR |
400 | Erro genérico de validação |
AUTH_REQUIRED |
401 | Autenticação necessária |
TOKEN_EXPIRED |
401 | Token JWT expirado |
Exemplo de Integração¶
JavaScript (Frontend)¶
⚠️ Segurança: A
public_keypode ficar no frontend, mas configureallowed_originsno dashboard para restringir acessos.
const PUBLIC_KEY = 'f47ac10b-58cc-4372-a567-0e02b2c3d479';
const BASE_URL = 'https://api.atendeaqui.com/api/onboarding';
// Headers padrão
const headers = {
'Content-Type': 'application/json',
'X-Onboarding-Key': PUBLIC_KEY
};
// 1. Carregar estrutura do fluxo
async function loadFlowStructure(language = 'pt-BR') {
const response = await fetch(
`${BASE_URL}/${PUBLIC_KEY}/structure?language=${language}`,
{ headers }
);
return await response.json();
}
// 2. Iniciar onboarding
async function startOnboarding(userId, clientId, userEmail) {
const response = await fetch(
`${BASE_URL}/${PUBLIC_KEY}/start`,
{
method: 'POST',
headers,
body: JSON.stringify({
external_user_id: userId,
external_user_email: userEmail,
client_id: clientId,
metadata: {
preferred_language: 'pt-BR'
}
})
}
);
return await response.json();
}
// 3. Completar etapa
async function completeStep(userId, stepKey, data = {}) {
const response = await fetch(
`${BASE_URL}/${PUBLIC_KEY}/progress/${userId}/complete-step`,
{
method: 'POST',
headers,
body: JSON.stringify({
step_key: stepKey,
step_data: data
})
}
);
return await response.json();
}
// 4. Consultar progresso
async function getProgress(userId) {
const response = await fetch(
`${BASE_URL}/${PUBLIC_KEY}/progress/${userId}`,
{ headers }
);
return await response.json();
}
// Exemplo de uso
async function runOnboarding() {
// Carregar estrutura
const flow = await loadFlowStructure();
console.log('Estrutura carregada:', flow);
// Iniciar para usuário
const progress = await startOnboarding('user_123', 'client_uuid', 'user@example.com');
console.log('Onboarding iniciado:', progress);
// Completar primeira etapa
const updated = await completeStep('user_123', 'welcome');
console.log('Etapa completada:', updated);
}
Integração com Widget Token (Frontend Seguro)¶
Para maior segurança, use tokens JWT de curta duração:
1) Seu backend obtém um token usando a public_key
2) Seu frontend usa Authorization: Bearer <token> nas chamadas
Fluxo:
Browser → Seu Backend → AtendeAqui (X-Onboarding-Key) → token curto → Browser → AtendeAqui (Bearer token)
Exemplo (Frontend React):
// Frontend: pedir token ao seu backend
const tokenRes = await fetch('/api/onboarding/widget-token', { credentials: 'include' });
const { token } = await tokenRes.json();
// Usar o token para consumir a API
const base = 'https://api.atendeaqui.com/api/onboarding';
const structure = await fetch(`${base}/structure?language=pt-BR`, {
headers: { Authorization: `Bearer ${token}` }
}).then(r => r.json());
const progress = await fetch(`${base}/start`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`
},
body: JSON.stringify({ external_user_id: userId, client_id })
}).then(r => r.json());
Exemplo (Seu Backend — Node/Express):
app.get('/api/onboarding/widget-token', async (req, res) => {
const r = await fetch('https://api.atendeaqui.com/api/onboarding/auth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Onboarding-Key': process.env.PUBLIC_KEY
},
body: JSON.stringify({
external_user_id: req.user.id,
client_id: req.user.client_id
})
});
const data = await r.json();
res.json({ token: data.token }); // expira em 10 min (padrão)
});
Exemplo (Seu Backend — Python):
import requests
from django.http import JsonResponse
from django.conf import settings
def widget_token(request):
r = requests.post(
'https://api.atendeaqui.com/api/onboarding/auth/token',
headers={'X-Onboarding-Key': settings.PUBLIC_KEY},
json={'external_user_id': str(request.user.id), 'client_id': str(request.user.client_id)}
)
data = r.json()
return JsonResponse({'token': data['token']})
Python (Backend) — com SDK¶
pip install atendeaqui
from atendeaqui import AtendeAquiClient, StepNotFoundError
client = AtendeAquiClient(
api_key='f47ac10b-58cc-4372-a567-0e02b2c3d479',
base_url='https://api.atendeaqui.com',
)
# Buscar estrutura
flow = client.onboarding.get_structure(language='pt-BR')
print(f"Flow: {flow.name} ({flow.step_count} steps)")
# Iniciar onboarding
progress = client.onboarding.start_flow(
user_id='user_123',
email='user@example.com',
metadata={'preferred_language': 'pt-BR', 'company': 'Empresa XYZ'},
)
# Completar etapa com dados
progress = client.onboarding.complete_step(
user_id='user_123',
step_key='welcome',
step_data={'accepted_terms': True},
)
print(f"Progresso: {progress.completion_percentage}%")
# Completar múltiplas etapas de uma vez
progress = client.onboarding.complete_steps(
user_id='user_123',
steps=[
{'step_key': 'config', 'step_data': {'api_key': 'xxx'}},
{'step_key': 'test'},
],
)
# Atualizar metadata do usuário
progress = client.onboarding.update_metadata(
user_id='user_123',
metadata={'plan': 'pro'},
)
# Consultar progresso com dados coletados
progress = client.onboarding.get_progress(user_id='user_123')
print(f"Status: {progress.status}")
print(f"Dados coletados: {progress.step_data}")
# Tratamento de erros
try:
client.onboarding.complete_step(user_id='user_123', step_key='invalid')
except StepNotFoundError as e:
print(f"Erro: {e.message}")
Boas Práticas¶
1. Cache de Estrutura¶
// Cachear estrutura do flow
const cachedFlow = localStorage.getItem('flow_structure');
if (!cachedFlow) {
const flow = await loadFlowStructure();
localStorage.setItem('flow_structure', JSON.stringify(flow));
}
2. Sincronização de Estado¶
// Sincronizar a cada 30 segundos
setInterval(async () => {
const progress = await getProgress(userId);
updateUI(progress);
}, 30000);
3. Validação Local¶
// Validar antes de enviar
function validateStepData(stepKey, data, flow) {
const step = flow.steps.find(s => s.step_key === stepKey);
if (step.step_type === 'FORM') {
const fields = step.step_config.form_fields;
for (const field of fields) {
if (field.required && !data[field.name]) {
throw new Error(`Campo ${field.label} é obrigatório`);
}
}
}
}
4. Tratamento de Idiomas¶
// Detectar idioma do navegador
const userLanguage = navigator.language || 'pt-BR';
const flow = await loadFlowStructure(userLanguage);