Clientes finais

Cadastro e organização dos clientes

Gerencie os clientes do seu SaaS sem alterar os identificadores usados na integração. A HookCloud separa dados cadastrais, vínculos de instância e operações destrutivas para reduzir riscos.

Modelo de dados

CampoPode editar?Uso
customer_idNãoUUID interno retornado pela HookCloud
external_customer_idNãoID estável do cliente no sistema do partner
customer_nameSimNome interno do cliente
customer_emailSimContato cadastral
customer_phoneSimContato cadastral
instance_keyNãoIdentificador estável da linha/instância
verified_nameNão por esta APINome oficial retornado pela Meta

Listar clientes

Use a listagem paginada para sincronizar telas, pesquisar cadastros e acompanhar slots.

bash
curl --request GET \
  --url 'https://api.hookcloud.app/functions/v1/swift-worker?route=list-partner-customers&page=1&page_size=50&status=active&search=clinica' \
  --header 'apikey: SUA_PUBLISHABLE_KEY' \
  --header 'Authorization: Bearer hc_partner_live_SUA_CHAVE'

Filtros: search, status, include_merged, include_erased, page e page_size.

Consultar um cliente

bash
curl --request GET \
  --url 'https://api.hookcloud.app/functions/v1/swift-worker?route=get-partner-customer&customer_id=UUID_DO_CLIENTE' \
  --header 'apikey: SUA_PUBLISHABLE_KEY' \
  --header 'Authorization: Bearer hc_partner_live_SUA_CHAVE'

Também é possível usar external_customer_id. O retorno inclui instâncias, slot comercial, histórico recente e estado de risco Meta.

Editar nome, e-mail e telefone

A atualização usa PATCH. Envie expected_updated_at para impedir que uma edição antiga sobrescreva uma alteração mais recente.

bash
curl --request PATCH \
  --url 'https://api.hookcloud.app/functions/v1/swift-worker?route=update-partner-customer' \
  --header 'apikey: SUA_PUBLISHABLE_KEY' \
  --header 'Authorization: Bearer hc_partner_live_SUA_CHAVE' \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: UUID_GERADO_PELO_SEU_BACKEND' \
  --data '{
    "customer_id": "UUID_DO_CLIENTE",
    "changes": {
      "customer_name": "Clínica Mais Vida",
      "customer_email": "contato@maisvida.com",
      "customer_phone": "5511999999999"
    },
    "expected_updated_at": "2026-07-23T12:00:00Z",
    "reason": "Correção cadastral"
  }'

Histórico de alterações

bash
GET https://api.hookcloud.app/functions/v1/swift-worker?route=get-partner-customer-history&customer_id=UUID&page=1&page_size=50

O histórico registra origem, ator, campos alterados, valores anteriores/novos, motivo, merge e movimentação de instâncias.

Mesclar cadastros duplicados

O cliente de origem é arquivado e suas instâncias passam para o cliente principal. Tokens, callbacks, números e instance_key não são modificados.

json
{
  "route": "merge-partner-customers",
  "source_customer_id": "UUID_DUPLICADO",
  "target_customer_id": "UUID_PRINCIPAL",
  "reason": "Cadastro duplicado"
}

Mover uma instância

Use para corrigir uma linha vinculada ao cliente errado. A operação altera somente partner_customer_id.

json
{
  "route": "move-partner-instance-to-customer",
  "instance_id": "UUID_DA_INSTANCIA",
  "target_customer_id": "UUID_DO_CLIENTE_CORRETO",
  "reason": "Número vinculado ao cliente incorreto"
}

Idempotência sem complicação

Em operações estruturais, envie um UUID no header Idempotency-Key. Se o seu backend repetir a mesma requisição depois de um timeout, a HookCloud devolve o resultado anterior sem executar tudo novamente.

http
Idempotency-Key: 6c10a60e-9b19-4f23-9be8-8b928af88e26

Não reutilize a mesma chave com outro payload; isso retorna 409 idempotency_key_reused.

Inativar não é apagar

O lifecycle normal deve usar deactivate-partner-customer e reactivate-partner-customer. A inativação remove callbacks, libera slots e preserva o histórico. Eliminação de dados pessoais é uma operação administrativa restrita à HookCloud.

Eventos para sincronizar seu sistema

  • hookcloud.partner.customer.updated
  • hookcloud.partner.customer.merged
  • hookcloud.partner.instance.moved
  • hookcloud.partner.customer.erasure_started
  • hookcloud.partner.customer.erased
  • hookcloud.partner.customer.erasure_failed

Os eventos usam o mesmo endpoint e a mesma assinatura HMAC descritos em Webhooks.

Cliente inativo e reconnect

Ao inativar o cliente, todas as instâncias são processadas. Chamadas repetidas sobre uma instância já inativa são idempotentes: a API não tenta remover novamente um callback que já está removed.

Cadastro pelo seu sistema e consulta de instâncias

  1. Cadastre ou reconcilie a empresa com upsert-partner-customer usando um external_customer_id estável.
  2. Consulte get-partner-webhook-endpoint; configure e valide o endpoint antes de iniciar a conexão.
  3. Crie a instância com create-customer-instance e abra o connect_url retornado.
  4. Após a conclusão, consulte get-partner-instance. Use list-partner-instances com external_customer_id para listar todas as linhas da empresa.
  5. Edite dados com update-partner-customer, sem alterar o ID externo.
  6. Ao encerrar, use as rotas deactivate-partner-instance ou deactivate-partner-customer. POST, PATCH e DELETE nessas rotas executam inativação lógica e remoção remota segura; não apagam o histórico.

Campos de contato ou metadata omitidos no upsert preservam os valores existentes. Upsert não reativa um cliente inativo nem ressuscita cadastro mesclado ou anonimizado; a reativação tem rota própria.

Para editar por ID externo, use external_customer_id como seletor fora de changes:

json
{
  "route": "update-partner-customer",
  "external_customer_id": "cliente_56790",
  "changes": {
    "customer_name": "Clínica Mais Vida",
    "customer_email": "novo@exemplo.com"
  },
  "expected_updated_at": "2026-09-10T12:00:00Z",
  "reason": "Contato atualizado no SaaS"
}

Use expected_updated_at obtido na consulta para detectar edição concorrente e um Idempotency-Key por operação. O cadastro da empresa não é o cadastro das pessoas que enviam mensagens: BSUID e username pertencem à identidade do destinatário no WhatsApp, não ao external_customer_id da empresa.

Conflitos que seu backend deve tratar

  • instance_customer_conflict: a instance_key já pertence a outro cliente. Use a movimentação explícita de instância; não tente reaproveitar a chave silenciosamente.
  • multiple_customer_instances: a desativação recebeu somente external_customer_id e a empresa tem várias linhas. Informe instance_id ou instance_key para escolher uma linha, ou use a inativação do cliente inteiro.
  • customer_changed_since_last_read: consulte novamente o cliente antes de reenviar uma edição concorrente.
  • cancel_pending: aguarde a conclusão da remoção antes de reativar. Clientes mesclados ou anonimizados não são reativados.

No upsert, campos de contato omitidos preservam o valor atual; null limpa o contato. Metadata deve ser objeto JSON. Métodos não aceitos retornam 405 com o cabeçalho Allow; não há rota PUT genérica.

Pronto para implementar?Use a OpenAPI, Postman Collection disponíveis na API Reference.

Chave automática e nome aprovado pela Meta

Na criação, external_customer_id identifica o cliente do seu sistema. A HookCloud gera uma instance_key imutável. Não envie uma chave personalizada para criar: isso retorna instance_key_server_managed. Uma chave já existente continua aceita como referência de compatibilidade, sem criar outro vínculo. Guarde o UUID e a chave retornados e reutilize a instância para reconectar. Para criar com segurança após timeout, envie Idempotency-Key (8 a 200 caracteres), estável para o número desejado: mesmo parceiro, cliente e chave reaproveitam a mesma instância; outra chave cria outra. A forma alternativa é idempotency_key no body. Sem essa chave, não repita a criação sem reconciliar o resultado.

customer_name e instance_name podem servir de nomes provisórios. Quando o nome de exibição for aprovado, instance_name acompanha o nome verificado da Meta. Tentar substituí-lo por outro nome retorna instance_name_managed_by_meta. Você pode guardar um apelido próprio em seu sistema, separado do nome oficial.

O GET existente traz verified_name, name_status, meta_business_id, meta_business_name, meta_waba_id, meta_waba_name, meta_synced_at e os metadados de sincronização disponíveis. A atualização automática é eventual: a rotina normal trabalha com alvo de 30 minutos mais uma distribuição de 0 a 60 segundos entre instâncias, acrescidos do tempo de cron e fila. Estados pendentes de nome, pagamento ou empresa também seguem essa rotina; não geram consultas permanentes a cada cinco minutos. Eventos administrativos assinados da identidade correspondente podem antecipar uma rodada: há uma janela limitada de três minutos e orçamento de até três tentativas por 30 minutos. Cada evento invalida somente o domínio pertinente; a nova leitura de empresa, pagamento ou perfil respeita um piso de 15 minutos desde a observação anterior. Cache, permissões, orçamento global da Meta e recuo após falhas podem ampliar o prazo. Portal e Admin consultam o cache local enquanto a atualização automática está ativa e a tela disponível; abrir a tela não dispara GETs à Meta. Não há garantia de atualização instantânea nem de que a Meta emita evento para toda alteração de cartão. Use hookcloud.instance.updated e hookcloud.instance.health_updated para atualizar seu cache e o GET para reconciliar.

Foto opcional do cliente

O cadastro pode ter uma foto privada para identificar o cliente no Portal. Isso não altera a imagem do perfil WhatsApp na Meta nem ocupa capacidade. Depois de obter o UUID do cliente, envie POST upload-partner-customer-avatar em multipart/form-data com customer_id e o binário em file: JPG, PNG ou WebP estático, até 2 MiB, 4096 pixels por lado e 16 megapixels (16.000.000 pixels no total). Imagens animadas não são aceitas. O escopo é customers.write; membros owner, admin e developer autorizados também podem alterar.

Leia avatar_url, avatar_url_expires_at e avatar_updated_at. A URL é assinada e temporária (aproximadamente cinco minutos); renove consultando o cadastro local e mostre as iniciais se a imagem falhar. Não compartilhe a URL como pública ou permanente. Para remover, envie POST remove-partner-customer-avatar com JSON {"customer_id":"UUID_DO_CLIENTE"}. Se a criação já teve sucesso e somente o envio da foto falhou, repita apenas a foto, sem criar outra instância.

Veja os campos completos de upload e a remoção.

Encerramento definitivo do cliente e das parcerias

Quando o cliente encerrar a assinatura no seu sistema, confirme o término efetivo e chame deactivate-partner-customer com seu external_customer_id. Não confunda a assinatura do cliente com o pacote contratado pelo parceiro na HookCloud: seu backend é responsável por comunicar esse encerramento.

  1. A HookCloud registra uma solicitação durável e bloqueia alterações que mudariam seu alcance.
  2. Desliga os números e autorizações desse cliente, em lotes e grupos seguros de WABA/autorização. Uma resposta perdida não autoriza repetir uma remoção já solicitada.
  3. Depois confere cada relação entre o portfólio HookCloud e os portfólios identificados do cliente. Só retira a relação inteira quando as provas atuais demonstram que nenhuma outra conexão ou ativo depende dela.
  4. Arquiva o cliente apenas quando a fase técnica e a comercial têm resultado final. Relações compartilhadas são preservadas e identificadas no resultado.

O POST retorna 202 enquanto houver trabalho ou pendência, com status=cancel_pending, archived=false e offboarding.job_id. Consulte GET get-customer-offboarding para acompanhar sem fazer GETs à Meta. Um POST repetido para o mesmo cliente continua a mesma solicitação; não crie novos cadastros para tentar destravá-la. O POST retorna 200 apenas quando o encerramento está concluído, com status=canceled e archived=true. O GET retorna 200 também para um job pendente: leia offboarding.status para distinguir.

Limite da conferência inicial: cada grupo que compartilha WABA ou autorização tem um orçamento de até 40 leituras na Meta e 45 segundos. Se não conseguir concluir essa conferência, o job informa action_required e customer_cleanup_scope_limit. O grupo não entra em repetição automática; a HookCloud precisa avaliar uma forma segura de organizar o encerramento. Não envie vários POSTs nem omita números para contornar esse limite. O GET de progresso continua sendo local e não gasta esse orçamento da Meta.

CampoComo interpretar
offboarding.technicalNúmeros confirmados, pendentes ou dependentes de ação.
offboarding.commercial.removedRelações com ausência confirmada na Meta.
offboarding.commercial.preserved_sharedRelações mantidas porque outra conexão, produto ou ativo ainda depende delas.
offboarding.issues[]Motivo estável em code e explicação para exibir em message.
offboarding.status=completedEncerramento concluído. Não significa que todas as parcerias foram removidas; confira os resultados comerciais.

Uma parceria HookCloud–empresa pode atender vários números, clientes ou produtos. Cancelar um cliente não autoriza afetar os demais. Histórico comprovadamente desconectado não é dependência ativa. Não envie business_id, WABA, token ou flags de exclusividade: a HookCloud deriva e verifica o alcance.

Os eventos de desconexão de cada instância continuam úteis, mas não substituem o resultado comercial do job. Veja os campos do encerramento, a consulta de progresso e a referência oficial da Meta sobre relações empresariais.