Olá, Marcelo.
Para esse cenário, eu avaliaria utilizar o External Contacts como uma camada de armazenamento operacional das informações dos clientes, em vez de distribuir os aproximadamente 20 mil registros entre várias Data Tables.
Em fluxos de chamadas inbound, o Genesys Cloud disponibiliza a variável nativa:
Call.ExternalContactId
Quando a interação já está associada a um External Contact, essa variável contém o identificador interno do contato. Nesse caso, não vejo necessidade de criar uma Data Action customizada apenas para pesquisar o registro.
O fluxo poderia utilizar diretamente a ação nativa Get External Contact, passando:
Call.ExternalContactId
A lógica seria semelhante a:
Chamada inbound
↓
Call.ExternalContactId está preenchido?
├── Sim
│ ↓
│ Get External Contact
│ ↓
│ Informações necessárias estão preenchidas?
│ ├── Sim → continuar o atendimento
│ └── Não → consultar a API do cliente
│
└── Não
↓
Consultar a API do cliente pelo ClientID
↓
Utilizar as informações retornadas
↓
Criar ou atualizar o External Contact
Na implementação que utilizo atualmente, o comportamento é parecido:
- O fluxo verifica se existe um External Contact associado à interação.
- Quando existe, recupera as informações já armazenadas.
- Se os campos necessários estiverem preenchidos, o fluxo continua sem consultar o backend do cliente.
- Se o contato não existir ou estiver sem as informações necessárias, o fluxo consulta a API do cliente.
- A resposta da API pode ser utilizada para criar ou enriquecer o External Contact, permitindo que interações futuras utilizem as informações já armazenadas.
Esse modelo reduz a dependência de consultas em tempo real ao sistema do cliente e utiliza o External Contacts como uma espécie de cache operacional.
Um ponto importante é que Call.ExternalContactId depende de a interação já ter sido associada a um contato.
Como você comentou que o ANI nem sempre é confiável, podem existir chamadas em que a variável esteja vazia ou NOT_SET. Nesse cenário, o fallback por ClientID ainda seria necessário.
Mesmo assim, isso não significa que todas as chamadas precisariam consultar o backend. A consulta seria realizada apenas quando:
- O External Contact não estivesse identificado.
- O contato ainda não tivesse sido criado.
- As informações necessárias não estivessem preenchidas.
- Os dados estivessem vencidos ou precisassem ser recalculados.
Para os dados adicionais, como propensão de reclamação ou classificação do cliente, poderiam ser utilizados custom fields do External Contact.
Atualização das informações
No meu caso atual, não tenho necessidade de atualizar constantemente os dados já armazenados.
Entretanto, se as informações precisassem permanecer sincronizadas com o sistema de origem, vejo duas alternativas principais.
A primeira, e que considero mais eficiente, seria o sistema do cliente enviar um webhook para o backend de integração quando alguma informação fosse modificada:
Alteração no sistema do cliente
↓
Webhook para o backend
↓
Atualização do External Contact
Dessa forma, somente os registros alterados seriam atualizados.
A segunda alternativa seria utilizar uma trigger programada para iniciar um Workflow ou chamar um backend responsável por consultar os registros modificados desde a última sincronização:
Scheduled Trigger
↓
Workflow ou backend
↓
Consulta por registros modificados
↓
Atualização dos External Contacts
Eu evitaria varrer os 20 mil registros a cada execução. O ideal seria utilizar algum campo como:
updatedAt
lastModifiedDate
lastSyncDate
para executar uma sincronização incremental.
Volume e limites
Se o volume de chamadas simultâneas ou de atualizações fosse muito alto, eu também recomendaria abrir um ticket com o suporte da Genesys.
O objetivo do ticket seria solicitar uma avaliação de capacidade e dos limites aplicáveis ao caso de uso, apresentando informações como:
- Chamadas por minuto no horário de pico.
- Quantidade de consultas por interação.
- Número esperado de atualizações.
- Concorrência máxima.
- Crescimento projetado.
- Endpoints utilizados.
A partir desses dados, a Genesys poderia avaliar se os limites atuais atendem ao cenário ou se existe alguma possibilidade de ajuste.
Minha proposta arquitetural seria:
External Contacts
= cache operacional no Genesys Cloud
API do cliente
= fonte oficial das informações
Call.ExternalContactId + Get External Contact
= consulta nativa dentro do fluxo
Webhook ou sincronização incremental
= atualização dos dados
API em tempo real
= fallback
Esse modelo não elimina completamente a API do cliente, mas evita chamá-la em todas as interações.
A consulta ao backend acontece apenas quando o Genesys Cloud ainda não possui um contato identificado ou quando os dados armazenados não são suficientes.
Você já avaliou utilizar Call.ExternalContactId com a ação nativa Get External Contact dessa forma?
Hi Marcelo,
For this scenario, I would consider using External Contacts as an operational storage layer for customer information instead of distributing approximately 20,000 records across multiple Data Tables.
In inbound call flows, Genesys Cloud provides the following built-in variable:
Call.ExternalContactId
When the interaction is already associated with an External Contact, this variable contains the contact's internal identifier. In that situation, I do not see a need to create a custom Data Action only to search for the record.
The flow could directly use the native Get External Contact action and pass:
Call.ExternalContactId
The logic could be structured as follows:
Inbound call
↓
Is Call.ExternalContactId populated?
├── Yes
│ ↓
│ Get External Contact
│ ↓
│ Are the required fields populated?
│ ├── Yes → continue the customer journey
│ └── No → query the customer API
│
└── No
↓
Query the customer API using ClientID
↓
Use the returned information
↓
Create or update the External Contact
The implementation I currently use follows a similar pattern:
- The flow verifies whether an External Contact is associated with the interaction.
- When a contact exists, the flow retrieves the information already stored in Genesys Cloud.
- If the required fields are populated, the flow continues without querying the customer's backend.
- If the contact does not exist or does not contain the required information, the flow calls the customer API.
- The API response can be used to create or enrich the External Contact so that future interactions can use the stored information.
This approach reduces the dependency on real-time calls to the customer's system and uses External Contacts as an operational cache.
One important consideration is that Call.ExternalContactId depends on the interaction already being associated with a contact.
Since you mentioned that ANI is not always reliable, there may be calls where this variable is empty or NOT_SET. In that situation, the fallback lookup using ClientID would still be required.
However, this does not mean that every interaction must query the backend. The API call would only be necessary when:
- The External Contact was not identified.
- The contact has not yet been created.
- The required information is missing.
- The stored data has expired or must be recalculated.
Additional information, such as complaint propensity or customer classification, could be stored in External Contact custom fields.
Keeping the information updated
In my current implementation, I do not need to continuously refresh information that has already been stored.
However, if the information had to remain synchronized with the source system, I would consider two main approaches.
The first, and in my opinion the most efficient, would be for the customer's system to send a webhook to the integration backend whenever a record changes:
Change in the customer system
↓
Webhook to the backend
↓
Update the External Contact
This way, only changed records would be updated.
The second option would be to use a scheduled trigger to start a Workflow or call a backend service responsible for retrieving records modified since the last synchronization:
Scheduled Trigger
↓
Workflow or backend
↓
Retrieve modified records
↓
Update External Contacts
I would avoid scanning all 20,000 records during every execution. An incremental synchronization should preferably use a field such as:
updatedAt
lastModifiedDate
lastSyncDate
Volume and platform limits
If the expected volume of concurrent calls or contact updates were high, I would also recommend opening a support ticket with Genesys.
The objective would be to request a capacity and rate-limit assessment for the use case, including information such as:
- Peak calls per minute.
- Number of lookups per interaction.
- Expected number of updates.
- Maximum concurrency.
- Projected growth.
- APIs and endpoints involved.
Based on these details, Genesys could evaluate whether the existing limits support the scenario or whether any adjustment is possible.
My proposed architecture would be:
External Contacts
= operational cache in Genesys Cloud
Customer API
= source of truth
Call.ExternalContactId + Get External Contact
= native lookup inside Architect
Webhook or incremental synchronization
= data-update mechanism
Real-time API lookup
= fallback
This model does not completely eliminate the customer API, but it avoids calling it during every interaction.
The backend is queried only when Genesys Cloud does not yet have an identified contact or when the stored information is insufficient.
Have you considered using Call.ExternalContactId together with the native Get External Contact action in this way?
------------------------------
Matheus Mendonca
------------------------------