Reten Docs
Operadores

Upsert por Lote

Crie ou atualize até 500 operadores em uma única operação, com relatório de resultado por item.

POST /api/integration/operators/batch-upsert

Cria ou atualiza (upsert) até 500 operadores em uma única operação. É o ponto de entrada de integração para carregar o quadro de operadores (vendedores, ativadores, agentes de call center) a partir de um sistema externo.

Auth: Obrigatório — permissão operator:batch-upsert

Sucesso parcial. Depois que o corpo passa na validação de formato, cada item é processado de forma independente: os que podem ser persistidos são persistidos, e os que falham são reportados em errors[] com um código estável — um item que falha não desfaz os demais. Sempre verifique summary.failed e errors na resposta.

Chave do upsert

Cada item é procurado entre os operadores existentes pelo par type + external_id. Se existir um operador com esse par, ele é atualizado (conta em summary.updated); caso contrário, é criado (summary.created). O mesmo external_id sob outro type é outro operador. Na atualização, metadata é mesclada com a existente: as chaves enviadas sobrescrevem as de mesmo nome, as não enviadas são mantidas, e enviar uma chave com null a remove. A mesclagem é recursiva (RFC 7386 JSON Merge Patch): os objetos aninhados são mesclados nível por nível, então você pode atualizar uma chave dentro de um objeto aninhado sem reenviar as irmãs. Qualquer outro valor substitui o anterior por completo, incluindo os arrays, que nunca são mesclados elemento a elemento. Enviar metadata: null esvazia o saco inteiro.

Corpo da Requisição

CampoTipoObrigatórioDescrição
itemsobject[]SimLista de operadores a gravar (mínimo 1, máximo 500).

Cada elemento de items:

CampoTipoObrigatórioDescrição
typeenumSimTipo de operador: SALESMAN, ACTIVATOR ou CALLCENTER. Parte da chave do upsert.
external_idstringSimIdentificador do operador no sistema externo. Parte da chave do upsert.
namestringSimNome do operador.
emailstringNãoE-mail. Deve ser um e-mail válido e não pode estar em uso por outro operador.
phonestringNãoNúmero de telefone.
metadataobjectNãoJSON arbitrário. Mesclado recursivamente com a metadata existente.

Exemplo

curl -X POST "https://api.reten.ai/api/integration/operators/batch-upsert" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "type": "SALESMAN",
        "external_id": "OP-001",
        "name": "Juan Pérez",
        "email": "juan.perez@example.com",
        "phone": "+56912345678",
        "metadata": { "zone": "north" }
      },
      {
        "type": "ACTIVATOR",
        "external_id": "OP-002",
        "name": "Ana López"
      },
      {
        "type": "CALLCENTER",
        "external_id": "OP-003",
        "name": "Carla Soto",
        "email": "juan.perez@example.com"
      }
    ]
  }'
const response = await fetch(
  "https://api.reten.ai/api/integration/operators/batch-upsert",
  {
    method: "POST",
    headers: {
      "x-api-key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      items: [
        { type: "SALESMAN", external_id: "OP-001", name: "Juan Pérez", email: "juan.perez@example.com", phone: "+56912345678", metadata: { zone: "north" } },
        { type: "ACTIVATOR", external_id: "OP-002", name: "Ana López" },
        { type: "CALLCENTER", external_id: "OP-003", name: "Carla Soto", email: "juan.perez@example.com" },
      ],
    }),
  },
);
const result = await response.json();
import requests

response = requests.post(
    "https://api.reten.ai/api/integration/operators/batch-upsert",
    headers={"x-api-key": "YOUR_API_KEY"},
    json={
        "items": [
            {"type": "SALESMAN", "external_id": "OP-001", "name": "Juan Pérez", "email": "juan.perez@example.com", "phone": "+56912345678", "metadata": {"zone": "north"}},
            {"type": "ACTIVATOR", "external_id": "OP-002", "name": "Ana López"},
            {"type": "CALLCENTER", "external_id": "OP-003", "name": "Carla Soto", "email": "juan.perez@example.com"},
        ],
    },
)
result = response.json()

Resposta 200 OK

Neste exemplo, OP-001 já existia e foi atualizado, OP-002 foi criado, e OP-003 falhou porque seu email já está em uso por outro operador:

{
  "summary": {
    "total": 3,
    "created": 1,
    "updated": 1,
    "failed": 1
  },
  "errors": [
    {
      "index": 2,
      "identifier": "OP-003",
      "error": "upsert_error",
      "message": "Email juan.perez@example.com already exists in operator 9c4b2e7a-1d5f-4a8b-b3c6-7e8f9a0b1c2d"
    }
  ]
}

Campos da resposta

CampoTipoDescrição
summary.totalnumberTotal de items enviados.
summary.creatednumberItems inseridos (operadores novos).
summary.updatednumberItems atualizados (operadores existentes modificados).
summary.failednumberItems que não puderam ser persistidos.
errorsobject[]Detalhe por item que falhou (vazio se todos tiveram sucesso).
errors[].indexnumberPosição (base 0) do item dentro do array items enviado.
errors[].identifierstringO external_id do item que falhou.
errors[].errorstringCódigo de erro estável (veja tabela abaixo).
errors[].messagestringMensagem legível para humanos/logs com a causa.

Códigos de erro por item

errorSignificado
upsert_errorO item não pôde ser persistido; message traz a causa (p. ex. um email já em uso por outro operador).

Erros (da request completa)

StatusDescrição
400items vazio ou com mais de 500 elementos; um item que não cumpre o formato (campo obrigatório ausente, tipo ou valor de enum inválido); ou uma propriedade não declarada aqui.
401Chave de API ausente ou inválida.
403A chave de API não tem a permissão operator:batch-upsert.