atendeaqui 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- atendeaqui-1.0.0/.github/copilot-instructions.md +82 -0
- atendeaqui-1.0.0/.gitignore +32 -0
- atendeaqui-1.0.0/LICENSE +21 -0
- atendeaqui-1.0.0/PKG-INFO +550 -0
- atendeaqui-1.0.0/README.md +529 -0
- atendeaqui-1.0.0/pyproject.toml +35 -0
- atendeaqui-1.0.0/src/atendeaqui/__init__.py +60 -0
- atendeaqui-1.0.0/src/atendeaqui/_http.py +138 -0
- atendeaqui-1.0.0/src/atendeaqui/_version.py +1 -0
- atendeaqui-1.0.0/src/atendeaqui/client.py +92 -0
- atendeaqui-1.0.0/src/atendeaqui/clients/__init__.py +205 -0
- atendeaqui-1.0.0/src/atendeaqui/clients/models.py +75 -0
- atendeaqui-1.0.0/src/atendeaqui/exceptions.py +78 -0
- atendeaqui-1.0.0/src/atendeaqui/onboarding/__init__.py +357 -0
- atendeaqui-1.0.0/src/atendeaqui/onboarding/models.py +168 -0
- atendeaqui-1.0.0/src/atendeaqui/py.typed +0 -0
- atendeaqui-1.0.0/tests/__init__.py +0 -0
- atendeaqui-1.0.0/tests/conftest.py +46 -0
- atendeaqui-1.0.0/tests/test_client.py +674 -0
- atendeaqui-1.0.0/tests/test_clients.py +335 -0
- atendeaqui-1.0.0/tests/test_exceptions.py +57 -0
- atendeaqui-1.0.0/tests/test_models.py +106 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# AtendeAqui Python SDK — Copilot Instructions
|
|
2
|
+
|
|
3
|
+
## Build & Test
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# Install (with dev deps)
|
|
7
|
+
pip install -e ".[dev]"
|
|
8
|
+
|
|
9
|
+
# Run all tests
|
|
10
|
+
pytest
|
|
11
|
+
|
|
12
|
+
# Run a single test file
|
|
13
|
+
pytest tests/test_client.py
|
|
14
|
+
|
|
15
|
+
# Run a single test
|
|
16
|
+
pytest tests/test_client.py::TestOnboarding::test_get_structure
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
No linter is configured in the project yet.
|
|
20
|
+
|
|
21
|
+
## Architecture
|
|
22
|
+
|
|
23
|
+
The SDK is a thin HTTP wrapper around the AtendeAqui REST API.
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
AtendeAquiClient (src/atendeaqui/client.py)
|
|
27
|
+
├── HttpClient (_http.py) — shared requests.Session, error handling
|
|
28
|
+
├── ClientsModule (clients/) — client.clients.*
|
|
29
|
+
└── OnboardingModule (onboarding/) — client.onboarding.*
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`AtendeAquiClient` requires at least one of `api_token` (Bearer token for admin endpoints) or `flow_key` (public UUID for onboarding endpoints). Both can be provided together.
|
|
33
|
+
|
|
34
|
+
`HttpClient` is the only transport layer. All modules receive it in their `__init__` and call `self._http.get/post/patch/put/delete(path, ...)`. It handles error parsing and maps API error codes to SDK exceptions via `ERROR_CODE_MAP` in `exceptions.py`.
|
|
35
|
+
|
|
36
|
+
## Key Conventions
|
|
37
|
+
|
|
38
|
+
### Models
|
|
39
|
+
All response models are plain `@dataclass` classes with a single `from_dict(cls, data: dict)` classmethod. They never raise — missing fields fall back to safe defaults (empty strings, `[]`, `{}`).
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
@dataclass
|
|
43
|
+
class MyModel:
|
|
44
|
+
field: str
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def from_dict(cls, data: dict) -> MyModel:
|
|
48
|
+
return cls(field=data.get('field', ''))
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
All model and module files use `from __future__ import annotations`.
|
|
52
|
+
|
|
53
|
+
### Adding a New Module
|
|
54
|
+
1. Create `src/atendeaqui/<module>/` with `__init__.py` (the module class) and `models.py`.
|
|
55
|
+
2. The module class takes `http: HttpClient` as its only required constructor arg. Add optional default params (e.g., `default_flow_key`) as keyword-only args.
|
|
56
|
+
3. Expose the module as a `@property` on `AtendeAquiClient` in `client.py`.
|
|
57
|
+
4. Export all public symbols from `src/atendeaqui/__init__.py`.
|
|
58
|
+
|
|
59
|
+
### Exception Hierarchy
|
|
60
|
+
All exceptions inherit from `AtendeAquiError(message, code, status_code, response)`. Specific codes are mapped in `exceptions.ERROR_CODE_MAP`. When adding new API error codes, add them to the map and create a new exception class if semantically distinct.
|
|
61
|
+
|
|
62
|
+
### Testing Pattern
|
|
63
|
+
Tests use the `responses` library to mock HTTP calls. Fixtures are in `tests/conftest.py`:
|
|
64
|
+
|
|
65
|
+
- `client` — `flow_key` only (public onboarding API)
|
|
66
|
+
- `admin_client` — `api_token` + `flow_key`
|
|
67
|
+
- `admin_only_client` — `api_token` only
|
|
68
|
+
|
|
69
|
+
All fixtures use `_base_url='https://test.atendeaqui.com.br/api'` (private param, for tests only). Mock the exact URL the module would call:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
@responses.activate
|
|
73
|
+
def test_something(self, client, mocked_responses):
|
|
74
|
+
mocked_responses.add(responses.GET, f'{BASE_URL}/api/resource/', json={...})
|
|
75
|
+
result = client.module.method()
|
|
76
|
+
assert result.field == 'expected'
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### API URL Structure
|
|
80
|
+
- Production: `https://api.atendeaqui.com.br/v1`
|
|
81
|
+
- Sandbox: `https://api.homolog.atendeaqui.com.br/v1`
|
|
82
|
+
- Paths use trailing slashes: `clients/`, `clients/{id}/`, `clients/{id}/team/`
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
|
|
7
|
+
# Distribution / packaging
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.egg-info/
|
|
11
|
+
*.egg
|
|
12
|
+
src/*.egg-info/
|
|
13
|
+
|
|
14
|
+
# Virtual environments
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
env/
|
|
18
|
+
|
|
19
|
+
# IDE
|
|
20
|
+
.idea/
|
|
21
|
+
.vscode/
|
|
22
|
+
*.sublime-project
|
|
23
|
+
*.sublime-workspace
|
|
24
|
+
|
|
25
|
+
# Testing
|
|
26
|
+
.pytest_cache/
|
|
27
|
+
.coverage
|
|
28
|
+
htmlcov/
|
|
29
|
+
|
|
30
|
+
# OS
|
|
31
|
+
.DS_Store
|
|
32
|
+
Thumbs.db
|
atendeaqui-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 AtendeAqui
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: atendeaqui
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: SDK Python para a plataforma AtendeAqui
|
|
5
|
+
Author: AtendeAqui
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Requires-Dist: requests>=2.28
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
19
|
+
Requires-Dist: responses>=0.23; extra == 'dev'
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# AtendeAqui SDK Python
|
|
23
|
+
|
|
24
|
+
SDK Python unificado para a plataforma AtendeAqui.
|
|
25
|
+
|
|
26
|
+
## Instalação
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install atendeaqui
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from atendeaqui import AtendeAquiClient
|
|
36
|
+
|
|
37
|
+
client = AtendeAquiClient(api_token="seu-bearer-token")
|
|
38
|
+
|
|
39
|
+
# Onboarding
|
|
40
|
+
flow = client.onboarding.get_structure(flow_key="uuid-do-flow", language="pt-BR")
|
|
41
|
+
progress = client.onboarding.start_flow(flow_key="uuid-do-flow", user_id="user-123", name="João Silva", email="u@example.com")
|
|
42
|
+
progress = client.onboarding.complete_step(flow_key="uuid-do-flow", user_id="user-123", step_key="welcome")
|
|
43
|
+
print(f"Progresso: {progress.completion_percentage}%")
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Autenticação
|
|
47
|
+
|
|
48
|
+
### Com api_token (recomendado)
|
|
49
|
+
|
|
50
|
+
O `api_token` é um Bearer token gerado no dashboard. Dá acesso a todos os módulos: clientes, onboarding (admin e progresso) e futuros módulos.
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
client = AtendeAquiClient(api_token="seu-bearer-token")
|
|
54
|
+
|
|
55
|
+
# Clientes
|
|
56
|
+
client.clients.list()
|
|
57
|
+
|
|
58
|
+
# Onboarding — passa flow_key por operação
|
|
59
|
+
client.onboarding.start_flow(flow_key="uuid-do-flow", user_id="user-123")
|
|
60
|
+
client.onboarding.list_flows()
|
|
61
|
+
client.onboarding.get_analytics(slug="meu-flow")
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Com flow_key default (atalho para um único flow)
|
|
65
|
+
|
|
66
|
+
Se o seu sistema interage com um único flow, passe `flow_key` na inicialização. Ele será usado como default em todos os métodos de onboarding (pode ser sobrescrito por chamada).
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
client = AtendeAquiClient(flow_key="f47ac10b-58cc-4372-a567-0e02b2c3d479")
|
|
70
|
+
|
|
71
|
+
# Usa o flow_key default — não precisa repetir
|
|
72
|
+
client.onboarding.get_structure()
|
|
73
|
+
client.onboarding.start_flow(user_id="user-123")
|
|
74
|
+
|
|
75
|
+
# Pode sobrescrever por chamada
|
|
76
|
+
client.onboarding.get_structure(flow_key="outro-flow-uuid")
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Com ambos (API admin + flow default)
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
client = AtendeAquiClient(
|
|
83
|
+
api_token="seu-bearer-token",
|
|
84
|
+
flow_key="f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
85
|
+
)
|
|
86
|
+
# Operações de progresso (usa flow_key default)
|
|
87
|
+
client.onboarding.start_flow(user_id="user-123")
|
|
88
|
+
# Operações admin (usa api_token)
|
|
89
|
+
client.onboarding.list_flows()
|
|
90
|
+
client.onboarding.get_analytics(slug="meu-flow")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Módulos
|
|
94
|
+
|
|
95
|
+
### Clientes (requer api_token)
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
admin = AtendeAquiClient(api_token="seu-bearer-token")
|
|
99
|
+
|
|
100
|
+
# Listar clientes
|
|
101
|
+
clientes = admin.clients.list(page=1, page_size=50)
|
|
102
|
+
|
|
103
|
+
# Criar cliente (client_id é gerado automaticamente se não fornecido)
|
|
104
|
+
novo = admin.clients.create(
|
|
105
|
+
full_name="Acme Corp",
|
|
106
|
+
email="contato@acme.com",
|
|
107
|
+
phone="1133334444",
|
|
108
|
+
identification_number="12.345.678/0001-90",
|
|
109
|
+
type_identification="CNPJ",
|
|
110
|
+
)
|
|
111
|
+
print(novo.client_id) # UUID gerado automaticamente
|
|
112
|
+
|
|
113
|
+
# Ou criar com ID do seu sistema (evita manter mapeamento de IDs)
|
|
114
|
+
novo = admin.clients.create(
|
|
115
|
+
full_name="Acme Corp",
|
|
116
|
+
email="contato@acme.com",
|
|
117
|
+
client_id="meu-sistema-123", # opcional: usa o ID do seu sistema local
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# Detalhes do cliente
|
|
121
|
+
cliente = admin.clients.get(client_id=novo.client_id)
|
|
122
|
+
|
|
123
|
+
# Atualizar cliente
|
|
124
|
+
admin.clients.update(novo.client_id, full_name="Acme Corp Ltda", phone="1199998888")
|
|
125
|
+
|
|
126
|
+
# Equipe do cliente
|
|
127
|
+
team = admin.clients.get_team(novo.client_id)
|
|
128
|
+
for member in team:
|
|
129
|
+
print(f"{member.full_name} (primary={member.is_primary})")
|
|
130
|
+
|
|
131
|
+
# Adicionar membro (cria usuário se não existir)
|
|
132
|
+
member = admin.clients.add_team_member(
|
|
133
|
+
client_id=novo.client_id,
|
|
134
|
+
user_email="joao@acme.com",
|
|
135
|
+
is_primary=True,
|
|
136
|
+
can_create_tickets=True,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Atualizar permissões
|
|
140
|
+
admin.clients.update_team_member(novo.client_id, member.id, can_edit_client=True)
|
|
141
|
+
|
|
142
|
+
# Remover membro
|
|
143
|
+
admin.clients.remove_team_member(novo.client_id, member.id)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Onboarding
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
FLOW = "uuid-do-flow"
|
|
150
|
+
|
|
151
|
+
# Estrutura do flow
|
|
152
|
+
flow = client.onboarding.get_structure(flow_key=FLOW, language="pt-BR")
|
|
153
|
+
|
|
154
|
+
# Iniciar onboarding
|
|
155
|
+
progress = client.onboarding.start_flow(
|
|
156
|
+
flow_key=FLOW,
|
|
157
|
+
user_id="user-123",
|
|
158
|
+
name="João Silva",
|
|
159
|
+
email="user@example.com",
|
|
160
|
+
metadata={"company": "Acme", "preferred_language": "pt-BR"},
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# Registrar início de um step (rastreamento, sem marcar como completo)
|
|
164
|
+
progress = client.onboarding.start_step(
|
|
165
|
+
user_id="user-123",
|
|
166
|
+
flow_key=FLOW,
|
|
167
|
+
step_key="welcome",
|
|
168
|
+
metadata={"source": "sidebar", "device": "desktop"}, # opcional
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Completar steps
|
|
172
|
+
progress = client.onboarding.complete_step(
|
|
173
|
+
user_id="user-123",
|
|
174
|
+
flow_key=FLOW,
|
|
175
|
+
step_key="welcome",
|
|
176
|
+
step_data={"accepted_terms": True},
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# Completar múltiplos steps (batch)
|
|
180
|
+
progress = client.onboarding.complete_steps(
|
|
181
|
+
user_id="user-123",
|
|
182
|
+
flow_key=FLOW,
|
|
183
|
+
steps=[
|
|
184
|
+
{"step_key": "config", "step_data": {"api_key": "xxx"}},
|
|
185
|
+
{"step_key": "test"},
|
|
186
|
+
],
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Pular step opcional
|
|
190
|
+
progress = client.onboarding.skip_step(user_id="user-123", flow_key=FLOW, step_key="tour")
|
|
191
|
+
|
|
192
|
+
# Atualizar metadata (merge)
|
|
193
|
+
progress = client.onboarding.update_metadata(
|
|
194
|
+
user_id="user-123",
|
|
195
|
+
flow_key=FLOW,
|
|
196
|
+
metadata={"plan": "pro"},
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
# Consultar progresso
|
|
200
|
+
progress = client.onboarding.get_progress(user_id="user-123", flow_key=FLOW)
|
|
201
|
+
print(progress.status) # IN_PROGRESS
|
|
202
|
+
print(progress.steps_completed) # ['welcome', 'config']
|
|
203
|
+
print(progress.step_data) # {'welcome': {'accepted_terms': True}, ...}
|
|
204
|
+
print(progress.completion_percentage) # 75
|
|
205
|
+
print(progress.flow_slug) # 'onboarding-clientes'
|
|
206
|
+
|
|
207
|
+
# Ações no flow
|
|
208
|
+
client.onboarding.complete_flow(user_id="user-123", flow_key=FLOW)
|
|
209
|
+
client.onboarding.restart_flow(user_id="user-123", flow_key=FLOW)
|
|
210
|
+
client.onboarding.abandon_flow(user_id="user-123", flow_key=FLOW)
|
|
211
|
+
|
|
212
|
+
# Token para widget frontend
|
|
213
|
+
token = client.onboarding.get_widget_token(flow_key=FLOW, user_id="user-123", ttl=600)
|
|
214
|
+
|
|
215
|
+
# Admin: listar flows e analytics (requer api_token)
|
|
216
|
+
flows = client.onboarding.list_flows()
|
|
217
|
+
analytics = client.onboarding.get_analytics(slug="meu-flow")
|
|
218
|
+
progress_list = client.onboarding.list_progress(slug="meu-flow")
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Exemplos de Uso
|
|
222
|
+
|
|
223
|
+
### Fluxo completo com dados de perfil
|
|
224
|
+
|
|
225
|
+
Quanto mais dados você enviar no `metadata` e `step_data`, mais personalizados serão os e-mails automáticos enviados pelo sistema. O sistema de e-mails usa IA para gerar conteúdo baseado no perfil e caso de uso do cliente.
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
from atendeaqui import AtendeAquiClient
|
|
229
|
+
|
|
230
|
+
client = AtendeAquiClient(flow_key="uuid-do-flow")
|
|
231
|
+
|
|
232
|
+
# 1. Iniciar o flow com metadata do usuário
|
|
233
|
+
# Esses dados são usados pela IA para personalizar e-mails de boas-vindas
|
|
234
|
+
progress = client.onboarding.start_flow(
|
|
235
|
+
user_id="empresa-456",
|
|
236
|
+
name="João Silva",
|
|
237
|
+
email="joao@agendapro.com.br",
|
|
238
|
+
metadata={
|
|
239
|
+
"company": "AgendaPro",
|
|
240
|
+
"sector": "tecnologia",
|
|
241
|
+
"role": "CTO",
|
|
242
|
+
"plan": "professional",
|
|
243
|
+
"preferred_language": "pt-BR",
|
|
244
|
+
},
|
|
245
|
+
)
|
|
246
|
+
# >>> E-mail de boas-vindas é enviado automaticamente (se configurado)
|
|
247
|
+
# >>> A IA usa nome, empresa e cargo para personalizar a saudação
|
|
248
|
+
|
|
249
|
+
# 2. Completar etapa de perfil com caso de uso
|
|
250
|
+
# step_data é JSON livre — envie tudo que descreve o cenário do cliente
|
|
251
|
+
progress = client.onboarding.complete_step(
|
|
252
|
+
user_id="empresa-456",
|
|
253
|
+
step_key="perfil",
|
|
254
|
+
step_data={
|
|
255
|
+
"uso_pretendido": "reuniões de vendas",
|
|
256
|
+
"tamanho_equipe": "até 10 pessoas",
|
|
257
|
+
"frequencia_uso": "diário",
|
|
258
|
+
"integracao_desejada": "Google Calendar",
|
|
259
|
+
},
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
# 3. Completar configuração técnica
|
|
263
|
+
progress = client.onboarding.complete_step(
|
|
264
|
+
user_id="empresa-456",
|
|
265
|
+
step_key="configuracao-api",
|
|
266
|
+
step_data={
|
|
267
|
+
"api_token": "EAAG...configurado",
|
|
268
|
+
"provider": "google",
|
|
269
|
+
"webhook_url": "https://agendapro.com.br/webhook",
|
|
270
|
+
},
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
# 4. Completar múltiplos steps de uma vez
|
|
274
|
+
progress = client.onboarding.complete_steps(
|
|
275
|
+
user_id="empresa-456",
|
|
276
|
+
steps=[
|
|
277
|
+
{
|
|
278
|
+
"step_key": "convidar-equipe",
|
|
279
|
+
"step_data": {
|
|
280
|
+
"membros_convidados": 5,
|
|
281
|
+
"emails": ["ana@agendapro.com.br", "pedro@agendapro.com.br"],
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"step_key": "personalizar-agenda",
|
|
286
|
+
"step_data": {
|
|
287
|
+
"horario_inicio": "08:00",
|
|
288
|
+
"horario_fim": "18:00",
|
|
289
|
+
"duracao_padrao": "30min",
|
|
290
|
+
"fuso_horario": "America/Sao_Paulo",
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
],
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
# 5. Completar o flow
|
|
297
|
+
client.onboarding.complete_flow(user_id="empresa-456")
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Integração com sistema existente (SaaS)
|
|
301
|
+
|
|
302
|
+
Exemplo de integração server-side: criar cliente + iniciar onboarding vinculado.
|
|
303
|
+
|
|
304
|
+
```python
|
|
305
|
+
from atendeaqui import AtendeAquiClient, NotFoundError
|
|
306
|
+
|
|
307
|
+
FLOW_KEY = "uuid-do-flow"
|
|
308
|
+
|
|
309
|
+
# api_token necessário para criar clientes
|
|
310
|
+
client = AtendeAquiClient(api_token="seu-bearer-token")
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def on_client_signup(client_data: dict):
|
|
314
|
+
"""Chamado após o cadastro de um novo cliente no seu sistema."""
|
|
315
|
+
|
|
316
|
+
# 1. Criar cliente no AtendeAqui usando o ID do seu sistema
|
|
317
|
+
# Isso evita manter um mapeamento separado de IDs
|
|
318
|
+
novo_cliente = client.clients.create(
|
|
319
|
+
full_name=client_data["company_name"],
|
|
320
|
+
email=client_data["email"],
|
|
321
|
+
client_id=client_data["id"], # usa o ID do seu sistema local
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
# 2. Iniciar onboarding vinculado ao cliente
|
|
325
|
+
progress = client.onboarding.start_flow(
|
|
326
|
+
flow_key=FLOW_KEY,
|
|
327
|
+
user_id=client_data["id"],
|
|
328
|
+
name=client_data["name"],
|
|
329
|
+
email=client_data["email"],
|
|
330
|
+
metadata={
|
|
331
|
+
"company": client_data.get("company_name", ""),
|
|
332
|
+
"sector": client_data.get("industry", ""),
|
|
333
|
+
"plan": client_data.get("plan", "free"),
|
|
334
|
+
},
|
|
335
|
+
client_id=novo_cliente.client_id, # vincula onboarding ao cliente
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
return progress
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def on_feature_configured(user_id: str, feature: str, config: dict):
|
|
342
|
+
"""Chamado quando o cliente configura uma feature no seu sistema."""
|
|
343
|
+
|
|
344
|
+
step_map = {
|
|
345
|
+
"api_setup": "configuracao-api",
|
|
346
|
+
"team_invite": "convidar-equipe",
|
|
347
|
+
"branding": "personalizar-marca",
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
step_key = step_map.get(feature)
|
|
351
|
+
if not step_key:
|
|
352
|
+
return
|
|
353
|
+
|
|
354
|
+
try:
|
|
355
|
+
progress = client.onboarding.complete_step(
|
|
356
|
+
flow_key=FLOW_KEY,
|
|
357
|
+
user_id=user_id,
|
|
358
|
+
step_key=step_key,
|
|
359
|
+
step_data=config,
|
|
360
|
+
)
|
|
361
|
+
return progress
|
|
362
|
+
except NotFoundError:
|
|
363
|
+
return None
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def check_onboarding_status(user_id: str) -> dict:
|
|
367
|
+
"""Verifica o status do onboarding para exibir no dashboard."""
|
|
368
|
+
|
|
369
|
+
try:
|
|
370
|
+
progress = client.onboarding.get_progress(flow_key=FLOW_KEY, user_id=user_id)
|
|
371
|
+
return {
|
|
372
|
+
"status": progress.status,
|
|
373
|
+
"percentage": progress.completion_percentage,
|
|
374
|
+
"is_completed": progress.is_completed,
|
|
375
|
+
"current_step": progress.current_step_title,
|
|
376
|
+
"steps_done": progress.steps_completed,
|
|
377
|
+
}
|
|
378
|
+
except NotFoundError:
|
|
379
|
+
return {"status": "NOT_STARTED", "percentage": 0}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Widget frontend com token JWT
|
|
383
|
+
|
|
384
|
+
```python
|
|
385
|
+
from atendeaqui import AtendeAquiClient
|
|
386
|
+
|
|
387
|
+
FLOW_KEY = "uuid-do-flow"
|
|
388
|
+
|
|
389
|
+
# Server-side: gerar token seguro para o frontend
|
|
390
|
+
server_client = AtendeAquiClient(flow_key=FLOW_KEY)
|
|
391
|
+
|
|
392
|
+
# Em uma view/endpoint do seu backend:
|
|
393
|
+
def get_onboarding_token(request):
|
|
394
|
+
token = server_client.onboarding.get_widget_token(
|
|
395
|
+
user_id=request.user.external_id,
|
|
396
|
+
client_id=request.user.client_id,
|
|
397
|
+
ttl=600, # 10 minutos
|
|
398
|
+
)
|
|
399
|
+
return {"token": token.token, "expires_in": token.expires_in}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Atualizar metadata em tempo real
|
|
403
|
+
|
|
404
|
+
Use `update_metadata` para enriquecer o perfil do cliente conforme ele interage com o sistema. Esses dados são usados pela IA nos e-mails de lembrete e parabéns.
|
|
405
|
+
|
|
406
|
+
```python
|
|
407
|
+
# Quando o cliente atualiza o plano
|
|
408
|
+
client.onboarding.update_metadata(
|
|
409
|
+
flow_key=FLOW_KEY,
|
|
410
|
+
user_id="empresa-456",
|
|
411
|
+
metadata={"plan": "enterprise", "seats": 50},
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
# Quando detectar a timezone do cliente
|
|
415
|
+
client.onboarding.update_metadata(
|
|
416
|
+
flow_key=FLOW_KEY,
|
|
417
|
+
user_id="empresa-456",
|
|
418
|
+
metadata={"timezone": "America/Sao_Paulo", "locale": "pt-BR"},
|
|
419
|
+
)
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Admin: monitorar onboarding
|
|
423
|
+
|
|
424
|
+
```python
|
|
425
|
+
# Requer api_token (Bearer token)
|
|
426
|
+
admin_client = AtendeAquiClient(api_token="seu-bearer-token")
|
|
427
|
+
|
|
428
|
+
# Listar todos os flows
|
|
429
|
+
flows = admin_client.onboarding.list_flows()
|
|
430
|
+
for flow in flows:
|
|
431
|
+
print(f"{flow['name']}: {flow['total_starts']} inícios, "
|
|
432
|
+
f"{flow['completion_rate']}% conclusão")
|
|
433
|
+
|
|
434
|
+
# Analytics de um flow específico
|
|
435
|
+
analytics = admin_client.onboarding.get_analytics(slug="onboarding-clientes")
|
|
436
|
+
print(f"Taxa de conclusão: {analytics.completion_rate}%")
|
|
437
|
+
print(f"Tempo médio: {analytics.average_completion_time}s")
|
|
438
|
+
print(f"Em progresso: {analytics.in_progress}")
|
|
439
|
+
print(f"Abandonados: {analytics.abandoned}")
|
|
440
|
+
|
|
441
|
+
# Drop-off por etapa
|
|
442
|
+
for step_key, data in analytics.step_drop_off.items():
|
|
443
|
+
print(f" {data['title']}: {data['completion_rate']}% "
|
|
444
|
+
f"({data['dropped']} desistiram)")
|
|
445
|
+
|
|
446
|
+
# Listar progresso de todos os usuários
|
|
447
|
+
progress_list = admin_client.onboarding.list_progress(
|
|
448
|
+
slug="onboarding-clientes",
|
|
449
|
+
page=1,
|
|
450
|
+
page_size=100,
|
|
451
|
+
)
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
## Referência: step_data e e-mails automáticos
|
|
455
|
+
|
|
456
|
+
O sistema de automação de e-mails usa IA para gerar conteúdo personalizado. Quanto mais dados você enviar via `step_data` e `metadata`, melhor a personalização.
|
|
457
|
+
|
|
458
|
+
### Parâmetros diretos do `start_flow`
|
|
459
|
+
|
|
460
|
+
| Parâmetro | Exemplo | Uso |
|
|
461
|
+
|-----------|---------|-----|
|
|
462
|
+
| `flow_key` | `"f47ac10b-..."` | UUID público do flow (obrigatório se não definido no client) |
|
|
463
|
+
| `name` | `"João Silva"` | Saudação nos e-mails, busca no admin |
|
|
464
|
+
| `email` | `"joao@acme.com"` | Destinatário dos e-mails automáticos |
|
|
465
|
+
| `client_id` | `"uuid-do-cliente"` | Opcional. Vincula o onboarding ao cliente (para tickets de suporte) |
|
|
466
|
+
|
|
467
|
+
### Dados recomendados no `metadata` (start_flow)
|
|
468
|
+
|
|
469
|
+
| Campo | Exemplo | Uso nos e-mails |
|
|
470
|
+
|-------|---------|--------------------|
|
|
471
|
+
| `company` | `"AgendaPro"` | Contextualizar a empresa |
|
|
472
|
+
| `sector` | `"tecnologia"` | Adaptar linguagem ao setor |
|
|
473
|
+
| `role` | `"CTO"` | Tom e nível técnico adequado |
|
|
474
|
+
| `plan` | `"professional"` | Sugestões baseadas no plano |
|
|
475
|
+
| `preferred_language` | `"pt-BR"` | Idioma do e-mail |
|
|
476
|
+
|
|
477
|
+
### Dados recomendados no `step_data` (complete_step)
|
|
478
|
+
|
|
479
|
+
| Step | Campos sugeridos | Uso nos e-mails |
|
|
480
|
+
|------|------------------|--------------------|
|
|
481
|
+
| Perfil/Caso de uso | `uso_pretendido`, `tamanho_equipe`, `frequencia_uso` | "Como você vai usar para reuniões de vendas com 10 pessoas..." |
|
|
482
|
+
| Configuração técnica | `provider`, `webhook_url` | "Você já configurou a integração com Google Calendar..." |
|
|
483
|
+
| Equipe | `membros_convidados`, `emails` | "Você convidou 5 membros — falta apenas personalizar a agenda" |
|
|
484
|
+
| Personalização | `horario_inicio`, `horario_fim`, `duracao_padrao` | "Sua agenda está configurada para atendimentos de 30min..." |
|
|
485
|
+
|
|
486
|
+
> **Dica:** Campos com nomes como `token`, `password`, `secret`, `key` e `credential` são automaticamente mascarados nos prompts da IA por segurança.
|
|
487
|
+
|
|
488
|
+
## Tratamento de Erros
|
|
489
|
+
|
|
490
|
+
```python
|
|
491
|
+
from atendeaqui import (
|
|
492
|
+
AtendeAquiClient,
|
|
493
|
+
StepNotFoundError,
|
|
494
|
+
NotFoundError,
|
|
495
|
+
ValidationError,
|
|
496
|
+
AtendeAquiError,
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
try:
|
|
500
|
+
client.onboarding.complete_step(flow_key=FLOW_KEY, user_id="user-123", step_key="invalid")
|
|
501
|
+
except StepNotFoundError as e:
|
|
502
|
+
print(f"Step não existe: {e.message}")
|
|
503
|
+
except NotFoundError as e:
|
|
504
|
+
print(f"Não encontrado: {e.message}")
|
|
505
|
+
except ValidationError as e:
|
|
506
|
+
print(f"Dados inválidos: {e.message}")
|
|
507
|
+
except AtendeAquiError as e:
|
|
508
|
+
print(f"Erro [{e.code}]: {e.message}")
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
### Hierarquia
|
|
512
|
+
|
|
513
|
+
```
|
|
514
|
+
AtendeAquiError
|
|
515
|
+
├── AuthenticationError # 401/403
|
|
516
|
+
├── NotFoundError # 404
|
|
517
|
+
├── ValidationError # 400
|
|
518
|
+
│ ├── StepNotFoundError
|
|
519
|
+
│ └── StepNotSkippableError
|
|
520
|
+
├── OriginNotAllowedError # CORS
|
|
521
|
+
├── RateLimitError # 429
|
|
522
|
+
└── ServerError # 5xx
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
## Estrutura do Pacote
|
|
526
|
+
|
|
527
|
+
```
|
|
528
|
+
atendeaqui/
|
|
529
|
+
├── __init__.py # AtendeAquiClient + exports
|
|
530
|
+
├── client.py # Cliente principal
|
|
531
|
+
├── _http.py # Transport HTTP compartilhado
|
|
532
|
+
├── exceptions.py # Exceções compartilhadas
|
|
533
|
+
├── clients/ # Módulo de Clientes
|
|
534
|
+
│ ├── __init__.py # ClientsModule
|
|
535
|
+
│ └── models.py # Client, TeamMember
|
|
536
|
+
└── onboarding/ # Módulo de Onboarding
|
|
537
|
+
├── __init__.py # OnboardingModule
|
|
538
|
+
└── models.py # FlowStructure, UserProgress, etc.
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
Novos módulos (tickets, knowledge_base, etc.) seguirão o mesmo padrão.
|
|
542
|
+
|
|
543
|
+
## Requisitos
|
|
544
|
+
|
|
545
|
+
- Python 3.10+
|
|
546
|
+
- requests >= 2.28
|
|
547
|
+
|
|
548
|
+
## Licença
|
|
549
|
+
|
|
550
|
+
MIT
|