Skip to content

Guia Prático: Agente de Call Center Completo

Este guia mostra como construir um agente de call center completo que demonstra todas as ferramentas de voz SIP funcionando juntas. Diferente de exemplos simples, esta é uma implementação real que você pode adaptar para uso em produção.

O Que Vamos Construir

Um agente de atendimento ao cliente que:

  1. Cumprimenta os clientes e pede identificação
  2. Coleta CPF pelo teclado (receive_dtmf) para consulta do cliente
  3. Resolve problemas ou...
  4. Transfere para atendentes humanos (transfer_call) quando necessário, ou...
  5. Navega URAs externas (send_dtmf) para consultar outros sistemas
  6. Encerra chamadas (end_dialog) capturando dados estruturados de resultado

Arquitetura de Integração

┌─────────────┐                    ┌──────────────┐     ┌─────────────┐
│   Seu PBX   │───SIP INVITE───▶│ SipPulse AI  │────▶│  Seu CRM    │
│             │   + headers       │              │     │             │
│ call-id:    │                   │              │     │             │
│ abc123      │   x-uid: abc123   │ thread.uid = │     │ Busca por   │
│             │   x-additional-   │ abc123       │     │ UID abc123  │
│             │   instructions:   │ (auto-criada) │     │             │
└─────────────┘   "caller: ..."   └──────────────┘     └─────────────┘

Pontos de Integração:

  • Headers SIP passam UID e contexto—não é necessária chamada de API antes da ligação
  • O sistema cria automaticamente a thread quando a chamada conecta
  • Após a chamada terminar, busque a thread por UID para extrair resultados
  • Use os dados do end_dialog para atualizar seu CRM/sistema de tickets

Início Rápido com Template

Quer pular a configuração manual? Vá em Agentes → Criar Agente → Templates e selecione "Agente de Call Center SIP". O template inclui todas as configurações deste guia—basta customizar os destinos de transferência e prompts para o seu negócio.

Pré-requisitos

Antes de começar:

Limitação do Playground de Voz

As ferramentas de voz SIP só funcionam durante chamadas SIP reais. Não podem ser testadas no Playground de Voz. Você precisa de uma conexão SIP real para testar este guia.


Parte 1: Configuração do Agente

1.1 Criar o Agente de Voz

  1. Navegue até Agentes e clique em Criar Agente
  2. Selecione Agente de Voz
  3. Nomeie: "Agente de Atendimento"
  4. Escolha um modelo com bom uso de ferramentas: gpt-5-mini ou claude-4-5-sonnet recomendados

1.2 Escrever as Instruções do Agente

Este prompt permite que o agente lide com múltiplos cenários e use todas as ferramentas de voz apropriadamente:

markdown
# Agente de Atendimento - Acme Corp

Você é o agente virtual de atendimento ao cliente da Acme Corp. Seu objetivo é ajudar
os clientes de forma eficiente mantendo um tom amigável e profissional.

## Variáveis de Contexto
Você tem acesso a estas variáveis da sessão do cliente:
- {{caller_id}} - O número de telefone do cliente
- {{inbound_did}} - Para qual linha da empresa ele ligou

## Fluxo de Identificação

### Passo 1: Saudação e Solicitação de CPF
Cumprimente o cliente calorosamente e peça que se identifique:
"Por favor, digite seu CPF de 11 dígitos usando o teclado do telefone. Pressione
cerquilha quando terminar, ou asterisco para apagar e recomeçar se cometer um erro."

### Passo 2: Coletar CPF (CRÍTICO)
- Use receive_dtmf para coletar exatamente 11 dígitos
- Timeout: 30 segundos

### Passo 3: Confirmar o CPF (OBRIGATÓRIO)
Após receber os dígitos, você DEVE:
1. Ler de volta CADA dígito individualmente: "Recebi: um, dois, três..."
2. Perguntar: "Está correto?"
3. Se NÃO: Peça desculpas e colete novamente
4. Se SIM: Prossiga para o atendimento

IMPORTANTE: NUNCA pule a confirmação. NUNCA leia como um número único.

## Fluxo de Atendimento

Após confirmar a identidade:
1. Pergunte como pode ajudar hoje
2. Tente resolver o problema diretamente
3. Se não conseguir resolver, transfira para o departamento apropriado

## Quando Transferir
Transfira a chamada quando:
- Cliente pedir explicitamente para falar com um humano
- Problema requer conhecimento técnico especializado
- Disputas financeiras ou reembolsos acima de R$ 500
- Cliente está frustrado após 2 tentativas de resolução
- Preocupações com segurança ou fraude

Ao transferir, explique o motivo e tranquilize o cliente.

## Destinos de Transferência
- sip:suporte@empresa.com - Suporte geral, dúvidas sobre conta
- sip:financeiro@empresa.com - Reembolsos, pagamentos, cobrança
- sip:tecnico@empresa.com - Problemas técnicos complexos

## Navegando Sistemas Externos
Se precisar consultar nosso sistema parceiro, use send_dtmf para navegar a URA:
- Pressione 1 para status da conta
- Pressione 2 para rastreamento de pedido

## Encerrando Chamadas
Encerre a chamada quando:
- Cliente confirmar que o problema foi resolvido
- Cliente se despedir
- Após transferência bem-sucedida (a ferramenta de transferência cuida disso)

Antes de encerrar, sempre pergunte: "Posso ajudar em mais alguma coisa?"

## Registrando Resultados da Chamada
Ao usar end_dialog, sempre capture:
- reason: Por que a chamada terminou (resolved, transferred, callback_requested, customer_ended)
- satisfaction: Satisfação expressa pelo cliente (1-5) se mencionou
- department: Qual departamento resolveu ou irá tratar
- resolution_notes: Breve resumo do que foi feito

1.3 Configurar Ferramentas de Voz

Navegue até Configuração de Chamada > Ferramentas e configure cada ferramenta:

Configuração de Ferramentas de Voz

Ative Encerrar Diálogo e configure o JSON Schema para capturar dados estruturados:

json
{
  "type": "object",
  "properties": {
    "reason": {
      "type": "string",
      "enum": ["resolved", "transferred", "callback_requested", "customer_ended"],
      "description": "Por que a chamada terminou"
    },
    "satisfaction": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5,
      "description": "Nota de satisfação se o cliente expressou"
    },
    "department": {
      "type": "string",
      "description": "Departamento que resolveu ou vai tratar o problema"
    },
    "resolution_notes": {
      "type": "string",
      "description": "Breve resumo do que foi resolvido ou do problema"
    }
  },
  "required": ["reason"]
}

Descrição:

Encerre a chamada quando o problema do cliente estiver resolvido ou ele quiser desligar.
Sempre pergunte se pode ajudar em mais alguma coisa antes de encerrar. Capture os dados
de resultado incluindo motivo, satisfação e notas de resolução.

Configuração do Transferir Chamada

Ative Transferir Chamada e adicione seus destinos:

DestinoDescrição
sip:suporte@empresa.comEquipe de suporte geral
sip:financeiro@empresa.comDepartamento financeiro
sip:tecnico@empresa.comSuporte técnico

Descrição:

Transferir para:
- suporte@empresa.com: Problemas gerais, dúvidas sobre conta, info de produtos
- financeiro@empresa.com: Reembolsos, disputas de pagamento, erros de cobrança, faturas
- tecnico@empresa.com: Problemas técnicos complexos, indisponibilidades, integrações

Configuração do Receber DTMF

Ative Receber DTMF com:

  • Timeout Padrão: 30 segundos

Descrição:

Coletar número de identificação do cliente (CPF) ou outra entrada numérica.
Sempre confirme os dígitos antes de prosseguir.

Configuração do Enviar DTMF

Ative Enviar DTMF com:

Descrição:

Navegar sistemas de URA externos ao consultar serviços parceiros.
Envie os dígitos apropriados baseado nas opções do menu.

1.4 Configurar Saudação

Defina Estratégia de Saudação como "Gerada por IA" com:

Cumprimente o cliente calorosamente, apresente-se como o assistente de IA da
Acme Corp, e inicie o processo de identificação pedindo que digite o CPF
usando o teclado do telefone.

Parte 2: Integração com PBX via Headers SIP

2.1 Como Funciona

Para chamadas SIP, o sistema cria threads automaticamente quando a chamada conecta ao seu agente. Você não precisa chamar nenhuma API antes da ligação começar. Em vez disso, você passa contexto para o agente via headers SIP que seu PBX adiciona ao SIP INVITE.

┌─────────────┐                              ┌──────────────────────────┐
│   Seu PBX   │──── SIP INVITE ─────────────▶│ <agent_id>@sip.sippulse.ai │
│             │     Headers:                 │                          │
│ call-id:    │       x-uid: abc123          │   Sistema cria thread    │
│ abc123      │       x-additional-          │   automaticamente com    │
│             │       instructions: ...      │   uid = "abc123"         │
└─────────────┘                              └──────────────────────────┘

Fluxo de integração:

  1. Habilite SIP no seu agente e copie o endereço SIP (ex: agt_xxxx@sip.sippulse.ai)
  2. Configure seu PBX para rotear chamadas para esse endereço
  3. Adicione headers SIP para passar contexto (UID, instruções adicionais)
  4. Após a chamada terminar, busque a thread por UID para extrair resultados

Onde Obter o Endereço SIP

O endereço SIP do agente é configurado na plataforma em Implantar > SIP. Veja o guia de Integração SIP para detalhes.

2.2 Headers SIP Suportados

HeaderObrigatórioDescrição
x-uidRecomendadoVincula a thread ao call-id do seu PBX para busca posterior
x-additional-instructionsOpcionalContexto extra para o agente (info do caller, DID, dados do cliente)

x-vars Ainda Não Suportado

O header x-vars ainda não é suportado. Use x-additional-instructions para passar contexto ao agente como instruções em linguagem natural.

2.3 Configurando Seu PBX

Asterisk (PJSIP)

ini
; extensions.conf
[incoming]
exten => _X.,1,NoOp(Chamada de ${CALLERID(num)})
 same => n,Set(PJSIP_HEADER(add,x-uid)=${UNIQUEID})
 same => n,Set(PJSIP_HEADER(add,x-additional-instructions)=Caller: ${CALLERID(num)}, DID: ${EXTEN})
 same => n,Dial(PJSIP/sippulse-trunk/${EXTEN})

FreeSWITCH

xml
<!-- dialplan/default.xml -->
<extension name="route_to_sippulse">
  <condition field="destination_number" expression="^(.*)$">
    <action application="set" data="sip_h_x-uid=${uuid}"/>
    <action application="set" data="sip_h_x-additional-instructions=Caller: ${caller_id_number}, DID: ${destination_number}"/>
    <action application="bridge" data="sofia/external/agt_xxxx@sip.sippulse.ai"/>
  </condition>
</extension>

Trunk SIP Genérico

A maioria dos sistemas SIP permite adicionar headers personalizados. Os headers principais a adicionar:

x-uid: <seu-call-id-do-pbx>
x-additional-instructions: Caller: +5511987654321, DID: +551140001234

UID vs Thread ID

  • Thread ID (thr_xxx): Identificador interno do SipPulse
  • UID: Seu identificador externo (call-id, número de ticket, etc.)

Você pode buscar threads usando qualquer um. Se o ID começa com thr_, é tratado como interno. Caso contrário, é buscado pelo UID.

2.4 Buscando Resultados da Chamada

Após a chamada terminar, busque a thread por UID para extrair os dados de resultado:

python
import json

def get_call_outcome(call_id: str) -> dict:
    """Busca thread pelo call-id do PBX e extrai dados de resultado"""

    response = requests.get(
        f"{BASE_URL}/threads/{call_id}",  # Usa UID diretamente
        headers={"api-key": API_KEY}
    )

    thread = response.json()
    outcome = {
        "end_dialog": None,
        "transfer_destination": None,
        "dtmf_collected": [],
    }

    # Procura no histórico de mensagens por chamadas de ferramentas
    for message in thread.get("history", []):
        tool_calls = message.get("tool_calls", [])

        for tool_call in tool_calls:
            func = tool_call.get("function", {})
            name = func.get("name")
            args = json.loads(func.get("arguments", "{}"))

            if name == "end_dialog":
                outcome["end_dialog"] = args
            elif name == "transfer_call":
                outcome["transfer_destination"] = args.get("to")
            elif name == "receive_dtmf":
                # Resultados DTMF estão nas mensagens de resposta de ferramenta
                pass

    # Também verifica respostas de ferramentas para dados DTMF
    for message in thread.get("history", []):
        if message.get("role") == "tool":
            content = message.get("content", "")
            if "digits" in content:
                try:
                    dtmf_data = json.loads(content)
                    outcome["dtmf_collected"].append(dtmf_data)
                except:
                    pass

    return outcome


# Exemplo de uso
outcome = get_call_outcome("pbx-call-abc123")
print(f"Resultado da chamada: {outcome}")
# {
#   'end_dialog': {'reason': 'resolved', 'satisfaction': 4, 'department': 'suporte'},
#   'transfer_destination': None,
#   'dtmf_collected': [{'digits': '12345678901', 'terminator': '#'}]
# }
javascript
async function getCallOutcome(callId) {
  const response = await fetch(
    `${BASE_URL}/threads/${callId}`,  // Usa UID diretamente
    { headers: { "api-key": API_KEY } }
  );

  const thread = await response.json();
  const outcome = {
    endDialog: null,
    transferDestination: null,
    dtmfCollected: [],
  };

  // Procura no histórico de mensagens por chamadas de ferramentas
  for (const message of thread.history || []) {
    for (const toolCall of message.tool_calls || []) {
      const { name, arguments: args } = toolCall.function;
      const parsedArgs = JSON.parse(args || "{}");

      if (name === "end_dialog") {
        outcome.endDialog = parsedArgs;
      } else if (name === "transfer_call") {
        outcome.transferDestination = parsedArgs.to;
      }
    }

    // Verifica respostas de ferramentas para dados DTMF
    if (message.role === "tool" && message.content?.includes("digits")) {
      try {
        const dtmfData = JSON.parse(message.content);
        outcome.dtmfCollected.push(dtmfData);
      } catch {}
    }
  }

  return outcome;
}

// Uso
const outcome = await getCallOutcome("pbx-call-abc123");
console.log("Resultado da chamada:", outcome);

2.5 Verificando Destino de Transferência (Pós-Chamada)

Quando o agente transfere uma chamada, o sistema automaticamente executa um SIP REFER para rotear a chamada ao destino. Este código serve para consultar para onde a chamada foi transferida após ela terminar—útil para relatórios e atualizações de CRM:

python
def get_transfer_destination(call_id: str) -> str | None:
    """Verifica se a chamada foi transferida e retorna o destino"""

    response = requests.get(
        f"{BASE_URL}/threads/{call_id}",
        headers={"api-key": API_KEY}
    )

    thread = response.json()

    for message in thread.get("history", []):
        for tool_call in message.get("tool_calls", []):
            if tool_call["function"]["name"] == "transfer_call":
                args = json.loads(tool_call["function"]["arguments"])
                return args.get("to")

    return None


# Uso
destination = get_transfer_destination("pbx-call-abc123")
if destination:
    print(f"Chamada foi transferida para: {destination}")
else:
    print("Chamada não foi transferida")
javascript
async function getTransferDestination(callId) {
  const response = await fetch(
    `${BASE_URL}/threads/${callId}`,
    { headers: { "api-key": API_KEY } }
  );

  const thread = await response.json();

  for (const message of thread.history || []) {
    for (const toolCall of message.tool_calls || []) {
      if (toolCall.function.name === "transfer_call") {
        const args = JSON.parse(toolCall.function.arguments);
        return args.to;
      }
    }
  }

  return null;
}

2.6 Exemplo Completo de Integração

Como as threads são criadas automaticamente pelo sistema quando chamadas SIP conectam, você só precisa tratar o evento de fim de chamada para extrair resultados. Aqui está um exemplo de webhook handler:

python
from flask import Flask, request, jsonify
import requests
import json

app = Flask(__name__)
API_KEY = "sua_chave_api"
BASE_URL = "https://api.sippulse.ai"


@app.route("/webhook/call-end", methods=["POST"])
def handle_call_end():
    """
    Chamado quando a chamada termina - busca thread por UID e atualiza CRM.

    O UID corresponde ao header x-uid que seu PBX adicionou ao SIP INVITE.
    """
    data = request.json
    call_id = data["call_id"]  # Mesmo valor que você definiu no header x-uid

    # Busca thread do SipPulse usando o UID
    response = requests.get(
        f"{BASE_URL}/threads/{call_id}",
        headers={"api-key": API_KEY}
    )
    thread = response.json()

    # Extrai dados de resultado do histórico da thread
    outcome = extract_outcome(thread)

    # Atualiza seu CRM/sistema de tickets
    if outcome["end_dialog"]:
        update_crm_ticket(
            call_id=call_id,
            reason=outcome["end_dialog"].get("reason"),
            satisfaction=outcome["end_dialog"].get("satisfaction"),
            notes=outcome["end_dialog"].get("resolution_notes"),
        )

    if outcome["transfer_destination"]:
        log_transfer(call_id, outcome["transfer_destination"])

    return jsonify({"status": "processed"})


def extract_outcome(thread: dict) -> dict:
    """Extrai dados de end_dialog e transferência do histórico da thread"""
    outcome = {"end_dialog": None, "transfer_destination": None}

    for message in thread.get("history", []):
        for tool_call in message.get("tool_calls", []):
            func = tool_call.get("function", {})
            name = func.get("name")
            args = json.loads(func.get("arguments", "{}"))

            if name == "end_dialog":
                outcome["end_dialog"] = args
            elif name == "transfer_call":
                outcome["transfer_destination"] = args.get("to")

    return outcome


def update_crm_ticket(call_id, reason, satisfaction, notes):
    """Atualiza seu CRM com resultado da chamada"""
    print(f"Atualizando CRM para {call_id}: {reason}, satisfação={satisfaction}")


def log_transfer(call_id, destination):
    """Registra transferência para relatórios"""
    print(f"Chamada {call_id} transferida para {destination}")


if __name__ == "__main__":
    app.run(port=5000)
javascript
const express = require("express");
const app = express();
app.use(express.json());

const API_KEY = "sua_chave_api";
const BASE_URL = "https://api.sippulse.ai";

/**
 * Chamado quando a chamada termina - busca thread por UID e atualiza CRM.
 * O UID corresponde ao header x-uid que seu PBX adicionou ao SIP INVITE.
 */
app.post("/webhook/call-end", async (req, res) => {
  const { call_id } = req.body; // Mesmo valor que você definiu no header x-uid

  // Busca thread do SipPulse usando o UID
  const response = await fetch(`${BASE_URL}/threads/${call_id}`, {
    headers: { "api-key": API_KEY }
  });
  const thread = await response.json();

  // Extrai dados de resultado do histórico da thread
  const outcome = extractOutcome(thread);

  // Atualiza seu CRM/sistema de tickets
  if (outcome.endDialog) {
    await updateCrmTicket(
      call_id,
      outcome.endDialog.reason,
      outcome.endDialog.satisfaction,
      outcome.endDialog.resolution_notes
    );
  }

  if (outcome.transferDestination) {
    await logTransfer(call_id, outcome.transferDestination);
  }

  res.json({ status: "processed" });
});

function extractOutcome(thread) {
  const outcome = { endDialog: null, transferDestination: null };

  for (const message of thread.history || []) {
    for (const toolCall of message.tool_calls || []) {
      const { name, arguments: args } = toolCall.function;
      const parsedArgs = JSON.parse(args || "{}");

      if (name === "end_dialog") {
        outcome.endDialog = parsedArgs;
      } else if (name === "transfer_call") {
        outcome.transferDestination = parsedArgs.to;
      }
    }
  }

  return outcome;
}

async function updateCrmTicket(callId, reason, satisfaction, notes) {
  console.log(`Atualizando CRM para ${callId}: ${reason}, satisfação=${satisfaction}`);
}

async function logTransfer(callId, destination) {
  console.log(`Chamada ${callId} transferida para ${destination}`);
}

app.listen(5000, () => console.log("Servidor webhook rodando na porta 5000"));

Parte 3: Exemplos de Conversas

Chamada Resolvida com Identificação DTMF

Agente: "Olá! Bem-vindo ao atendimento da Acme Corp. Sou seu assistente de IA. Para atendê-lo, por favor digite seu CPF de 11 dígitos usando o teclado do telefone. Pressione cerquilha quando terminar, ou asterisco para recomeçar se errar."

Cliente digita: 1-2-3-4-5-6-7-8-9-0-1-#

Agente: "Obrigado! Recebi: um, dois, três, quatro, cinco, seis, sete, oito, nove, zero, um. Está correto?"

Cliente: "Sim, está certo."

Agente: "Perfeito, encontrei sua conta, João. Como posso ajudar você hoje?"

Cliente: "Preciso verificar o status do meu pedido."

Agente: "Posso ajudar com isso. Deixa eu consultar seus pedidos recentes... Vejo que o pedido #12345 foi enviado ontem e deve chegar até sexta-feira. Gostaria do código de rastreamento?"

Cliente: "Não, está ótimo. Obrigado!"

Agente: "De nada! Posso ajudar em mais alguma coisa?"

Cliente: "Não, é só isso."

Agente: "Ótimo! Obrigado por ligar para a Acme Corp. Tenha um excelente dia!"

Agente encerra a chamada com: {reason: "resolved", satisfaction: null, department: "suporte"}

Transferência para Atendente Humano

Cliente: "Fui cobrado duas vezes pelo meu pedido e quero reembolso!"

Agente: "Peço desculpas pelo inconveniente. Vejo que isso é uma questão de cobrança que nossa equipe financeira pode resolver diretamente para você. Vou transferir você agora—eles poderão processar seu reembolso. Por favor, aguarde um momento."

Agente transfere para sip:financeiro@empresa.com

Tratamento de Erros na Coleta DTMF

Agente: "...Recebi: um, dois, três, quatro. Está correto?"

Cliente: "Não, eu errei."

Agente: "Sem problemas! Vamos tentar novamente. Por favor, digite seu CPF de 11 dígitos. Lembre-se, pressione asterisco para apagar e recomeçar, cerquilha quando terminar."

Cliente pressiona asterisco, depois digita o número correto


Parte 4: Como Funciona Internamente

Fluxo de Transferência

Quando o agente decide transferir:

  1. LLM gera chamada de ferramenta com o destino
  2. Sistema de voz recebe a solicitação de transferência
  3. Agente termina de falar ("Vou transferir você...")
  4. SIP REFER é enviado para seu trunk SIP
  5. Chamada é transferida para o destino
Agente fala → Aguarda TTS completar → SIP REFER → Chamada transferida

Fluxo de Coleta DTMF

A coleta DTMF tem tratamento sofisticado:

  1. Buffer antecipado: Cliente pode começar a digitar antes do agente terminar de falar
  2. Término inteligente: Encerra na quantidade esperada de dígitos OU tecla terminadora (#)
  3. Capacidade de reset: Asterisco (*) limpa o buffer para recomeçar
  4. Tratamento de timeout: Fallback gracioso se não receber entrada
Agente: "Digite seu CPF..."

       ├── Cliente digita imediatamente (buffer)

       └── Agente termina de falar

           └── Coleta inicia/continua

               ├── # pressionado → Retorna dígitos
               ├── 11 dígitos → Retorna dígitos
               ├── * pressionado → Limpa, aguarda entrada
               └── Timeout → Retorna parcial ou vazio

Parte 5: Solução de Problemas

DTMF Não Está Sendo Coletado

SintomaCausa ProvávelSolução
Ferramenta nunca disparaFerramenta não habilitadaVerifique Configuração de Chamada > Ferramentas
Nenhum dígito recebidoProblema de codec SIPVerifique método DTMF (RFC 2833 ou SIP INFO)
Dígitos parciaisLatência de redeAumente timeout, verifique conexão
Dígitos não confirmadosProblema no promptAtualize instruções do agente para sempre confirmar

Transferência Não Funciona

SintomaCausa ProvávelSolução
Transferência falhaURI SIP inválidoVerifique formato: sip:usuario@dominio
Destino erradoInstruções não clarasSeja mais específico na descrição da ferramenta
Loops de transferênciaAgente confusoAdicione condições mais claras no prompt
Erro SIPTrunk não suporta REFERVerifique com seu provedor SIP
SintomaCausa ProvávelSolução
Nunca encerraFerramenta não habilitadaHabilite Encerrar Diálogo nas ferramentas
Encerra muito cedoCondições muito amplasRefine descrição e prompt
Dados faltandoSchema não correspondeVerifique se JSON Schema é válido
Dados parciaisAgente não preenche todos os camposTorne campos obrigatórios explícitos no prompt

Busca por UID Falha

SintomaCausa ProvávelSolução
Thread não encontradaUID não correspondeVerifique correspondência exata do UID
Thread erradaUIDs duplicadosGaranta UIDs únicos por organização
Histórico vazioThread não usadaVerifique se a thread foi realmente usada na chamada

Documentação Relacionada