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:

  1. Ter um fluxo criado no dashboard
  2. Obter a Public Key do fluxo
  3. Configurar allowed_origins (recomendado para produção)
  4. (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_key pode ficar no frontend, mas configure allowed_origins no 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);

Próximos Passos