Criar Atividades em Lote
Criar múltiplas atividades em uma única requisição.
POST /api/activities/bulk
Crie até 200 atividades em uma única requisição. Cada item segue o mesmo esquema do endpoint individual Criar Atividade.
Auth: Obrigatório — permissão activity:create
Corpo da Requisição
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
items | array | Sim | Array de objetos de atividade (mín. 1, máx. 200) |
Cada item em items tem os mesmos campos que o corpo da requisição de Criar Atividade:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
type | string | Sim | TASK |
reason | string | Sim | Código do motivo: apenas letras minúsculas, dígitos e _ (^[a-z0-9_]+$), máximo de 100 caracteres. Um código que não está no catálogo de motivos do tenant é adicionado a ele na hora |
channel | string | Sim | SALESMAN, CALLCENTER |
commerce_id | UUID | Condicional | ID do comércio alvo. Envie este campo ou commerce_external_id: pelo menos um é obrigatório. Se você enviar os dois, commerce_id prevalece |
commerce_external_id | string | Condicional | Comércio alvo por ID externo (máximo de 255 caracteres). Se nenhum comércio o tiver, a API cria um comércio placeholder com esse ID externo |
idempotency_key | string | Sim | Chave única por tenant (evita duplicados) |
scheduled_at | ISO 8601 | Sim | Quando a atividade deve ser executada |
intent_category | string | Não | ONBOARDING, MARKETING, COLLECTION, RETENTION, NOTIFICATION, SURVEY ou VALIDATION. Padrão NOTIFICATION |
suggested_execution_time | ISO 8601 | Não | Horário sugerido para execução |
user_status | string | Não | Contexto de status do usuário |
score | integer | Não | Pontuação de prioridade |
assignment_reason | string | Não | Motivo da atribuição |
activity_details | object | Sim, para TASK | Atribuição de rota e operador (ver Criar Atividade). Um item TASK sem este campo falha com validation_error |
Exemplo
curl -X POST https://api.reten.ai/api/activities/bulk \
-H "Authorization: Bearer <token>" \
-H "x-tenant-id: <tenant-id>" \
-H "x-project-id: <project-id>" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"type": "TASK",
"reason": "monthly_visit",
"channel": "SALESMAN",
"commerce_id": "880e8400-e29b-41d4-a716-446655440000",
"idempotency_key": "task-2025-01-15-001",
"scheduled_at": "2025-01-16T09:00:00.000Z",
"activity_details": {
"assigned_route_id": "dd0e8400-e29b-41d4-a716-446655440000",
"assigned_operator_id": "cc0e8400-e29b-41d4-a716-446655440000"
}
},
{
"type": "TASK",
"reason": "monthly_visit",
"channel": "CALLCENTER",
"commerce_external_id": "SHOP-0042",
"idempotency_key": "task-2025-01-15-002",
"scheduled_at": "2025-01-16T09:00:00.000Z",
"activity_details": {
"assigned_route_external_id": "ROUTE-07",
"assigned_operator_external_id": "AGENT-15"
}
}
]
}'const response = await fetch("https://api.reten.ai/api/activities/bulk", {
method: "POST",
headers: {
"Authorization": "Bearer <token>",
"x-tenant-id": "<tenant-id>",
"x-project-id": "<project-id>",
"Content-Type": "application/json",
},
body: JSON.stringify({
items: [
{
type: "TASK",
reason: "monthly_visit",
channel: "SALESMAN",
commerce_id: "880e8400-e29b-41d4-a716-446655440000",
idempotency_key: "task-2025-01-15-001",
scheduled_at: "2025-01-16T09:00:00.000Z",
activity_details: {
assigned_route_id: "dd0e8400-e29b-41d4-a716-446655440000",
assigned_operator_id: "cc0e8400-e29b-41d4-a716-446655440000",
},
},
{
type: "TASK",
reason: "monthly_visit",
channel: "CALLCENTER",
commerce_external_id: "SHOP-0042",
idempotency_key: "task-2025-01-15-002",
scheduled_at: "2025-01-16T09:00:00.000Z",
activity_details: {
assigned_route_external_id: "ROUTE-07",
assigned_operator_external_id: "AGENT-15",
},
},
],
}),
});
const result = await response.json();import requests
response = requests.post(
"https://api.reten.ai/api/activities/bulk",
headers={
"Authorization": "Bearer <token>",
"x-tenant-id": "<tenant-id>",
"x-project-id": "<project-id>",
},
json={
"items": [
{
"type": "TASK",
"reason": "monthly_visit",
"channel": "SALESMAN",
"commerce_id": "880e8400-e29b-41d4-a716-446655440000",
"idempotency_key": "task-2025-01-15-001",
"scheduled_at": "2025-01-16T09:00:00.000Z",
"activity_details": {
"assigned_route_id": "dd0e8400-e29b-41d4-a716-446655440000",
"assigned_operator_id": "cc0e8400-e29b-41d4-a716-446655440000",
},
},
{
"type": "TASK",
"reason": "monthly_visit",
"channel": "CALLCENTER",
"commerce_external_id": "SHOP-0042",
"idempotency_key": "task-2025-01-15-002",
"scheduled_at": "2025-01-16T09:00:00.000Z",
"activity_details": {
"assigned_route_external_id": "ROUTE-07",
"assigned_operator_external_id": "AGENT-15",
},
},
],
},
)
result = response.json()Resposta 201 Created
Depois que o corpo passa na validação, a API sempre responde 201 Created, mesmo que todos os itens falhem. Os itens são processados um de cada vez, em ordem, e um item que falha não afeta os demais. O corpo informa o resultado de cada item; index é a posição do item em items, contando a partir de 0.
| Campo | Tipo | Descrição |
|---|---|---|
summary | object | Contadores: total (itens recebidos), created, skipped e failed |
items | array | Atividades criadas: index, idempotencyKey, activityId |
skipped | array | Itens cuja idempotency_key já pertence a uma atividade do projeto ativo: index, idempotencyKey, existingActivityId. Nada é criado nem alterado, qualquer que seja o status dessa atividade |
errors | array | Itens que falharam: index, idempotencyKey, error, message |
error é um destes códigos, e message é a mensagem da API para esse item:
error | Quando | Exemplo de message |
|---|---|---|
validation_error | O item passa na validação do corpo, mas viola uma regra de criação | Se requiere al menos uno de los campos commerce_id o commerce_external_id., TASK activities require activityDetails, assigned_route_id is required for TASK activities |
not_found | commerce_id, assigned_route_id ou assigned_operator_id não existe | Commerce not found, Route not found, Operator not found |
creation_error | Qualquer outra falha — por exemplo, a idempotency_key já é usada por uma atividade de outro projeto do tenant | La clave de idempotencia ya está en uso. |
Uma idempotency_key já usada em outro projeto é informada como um item creation_error, nunca como um HTTP 409.
Exemplo para um lote de três itens: o primeiro é criado, o segundo tem uma idempotency_key que já existe no projeto e o terceiro referencia um comércio que não existe.
{
"summary": {
"total": 3,
"created": 1,
"skipped": 1,
"failed": 1
},
"items": [
{
"index": 0,
"idempotencyKey": "task-2025-01-15-001",
"activityId": "ee0e8400-e29b-41d4-a716-446655440000"
}
],
"skipped": [
{
"index": 1,
"idempotencyKey": "task-2025-01-14-007",
"existingActivityId": "ff0e8400-e29b-41d4-a716-446655440000"
}
],
"errors": [
{
"index": 2,
"idempotencyKey": "task-2025-01-15-003",
"error": "not_found",
"message": "Commerce not found"
}
]
}Respostas de Erro
| Status | Descrição |
|---|---|
400 | Corpo inválido: items está vazio ou tem mais de 200 elementos, ou um item tem um campo inválido ou ausente, ou um campo que o endpoint não aceita. Nada é criado |
401 | Token de autenticação ausente ou inválido |
403 | Falta a permissão activity:create |