wonittecnologia / interage-sdk-php
SDK PHP oficial da API pública de clientes da plataforma Interage+ (Wonit).
Package info
github.com/WonitTecnologia/interage-sdk-php
pkg:composer/wonittecnologia/interage-sdk-php
Requires
- php: >=8.1
- ext-curl: *
- ext-json: *
Requires (Dev)
- phpunit/phpunit: ^10.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-25 04:46:19 UTC
README
SDK PHP oficial da API pública de clientes da plataforma Interage+ (Wonit).
- PHP 8.1+, sem dependências — usa só as extensões
curlejson. - Respostas tipadas: cada chamada devolve objetos com propriedades
readonly, datas comoDateTimeImmutablee campos ausentes comonull. - Mesmo contrato do SDK Go.
Instalação
composer require wonittecnologia/interage-sdk-php
Início rápido
<?php require 'vendor/autoload.php'; use WonitTecnologia\Interage\Client; // Domínio do seu tenant (https:// é adicionado automaticamente). $cli = new Client('SEU-TENANT.wonit.cloud', 'sk_xxxxxxxxxxxx'); $campanhas = $cli->campaigns->list(); foreach ($campanhas->items as $c) { echo $c->name, ' — ', $c->status, ' — ', $c->totalContacts, PHP_EOL; }
Configuração
new Client(string $baseUrl, string $token, ?Options $options = null)
| Parâmetro | Obrigatório | Descrição |
|---|---|---|
$baseUrl |
sim | Domínio do tenant (ex.: SEU-TENANT.wonit.cloud). Sem scheme, o SDK usa https://. |
$token |
sim | Token de API sk_<valor> (painel administrativo → Tokens de API). |
Options::$timeout |
não | Tempo máximo de cada requisição, em segundos (padrão: 30). |
Options::$insecure |
não | Usa http:// quando a baseUrl vem sem scheme. Só para desenvolvimento local. |
Options::$transport |
não | Transporte HTTP próprio (proxy, cliente HTTP do seu framework, testes). Padrão: curl. |
use WonitTecnologia\Interage\Options; $cli = new Client('SEU-TENANT.wonit.cloud', 'sk_xxx', new Options(timeout: 10));
As permissões de cada rota (leitura, listagem, criação, alteração, remoção) são configuradas por token no painel. Token ausente, inválido, expirado ou revogado responde 401; token válido sem a rota ou sem a ação responde 403.
Domínios
| Propriedade | Cobre |
|---|---|
$cli->campaigns |
Campanhas de disparo WhatsApp |
$cli->messages |
Instâncias, templates HSM e envio de mensagens |
$cli->omni |
Filas, agentes e conversas |
$cli->contacts |
Central de contatos |
$cli->telephony |
Ramais, histórico de ligações, click-to-call e gravações |
Campaigns — campanhas de disparo WhatsApp
Criar campanha com CSV
O CSV deve ter delimitador , ou ; e uma coluna de telefone (phone, telefone,
numero, celular ou whatsapp). Colunas opcionais: name, email, company.
use WonitTecnologia\Interage\Enum\CollisionPolicy; use WonitTecnologia\Interage\Request\CreateCampaignRequest; $criada = $cli->campaigns->create(new CreateCampaignRequest( name: 'Black Friday', instanceId: '<instance_id>', // $cli->messages->listInstances() templateId: '<gupshup_id>', // $cli->messages->listTemplates() collisionPolicy: CollisionPolicy::UpdateEmpty, fileName: 'contatos.csv', fileContent: file_get_contents('contatos.csv'), templateParams: ['10%'], startAt: new DateTimeImmutable('2026-11-27 09:00'), autoStart: true, replyWithoutContext: true, // mensagem sem citar o disparo também conta como resposta… replyWindowHours: 48, // …se chegar em até 48h (1 a 72; padrão da API: 24) )); // A importação é assíncrona: nasce "pending" e passa a "ready" ao terminar. echo $criada->campaignId;
Listar, detalhar e controlar
use WonitTecnologia\Interage\Enum\CampaignStatus; $pagina = $cli->campaigns->list(status: CampaignStatus::Running, pageSize: 50); $campanha = $cli->campaigns->get($id); $cli->campaigns->start($id); // ready | paused | scheduled → running $cli->campaigns->pause($id); // running → paused $cli->campaigns->cancel($id); // → canceled (não reinicia) $cli->campaigns->delete($id); // não remove em execução/processamento if (CampaignStatus::tryFrom($campanha->status) === CampaignStatus::Completed) { /* ... */ }
Messages — instâncias, templates e envio
use WonitTecnologia\Interage\Request\SendMessageRequest; use WonitTecnologia\Interage\Request\SendTemplateRequest; $instancias = $cli->messages->listInstances(); $templates = $cli->messages->listTemplates(status: 'APPROVED', instanceId: '<instance_id>'); // Template HSM (inicia conversa) $envio = $cli->messages->sendTemplate(new SendTemplateRequest( to: '5547999999999', templateId: '<gupshup_id>', instanceId: '<instance_id>', params: ['Maria'], )); // Mensagem livre, dentro da sessão de 24h de uma conversa ativa $cli->messages->sendMessage(SendMessageRequest::text('<protocolo>', 'Olá!')); $cli->messages->sendMessage(SendMessageRequest::media('<protocolo>', 'image', 'https://.../foto.jpg', caption: 'Veja')); $cli->messages->sendMessage(SendMessageRequest::location('<protocolo>', -26.91, -48.66, 'Loja Centro')); // Status de entrega $status = $cli->messages->getMessageStatus($envio->internalMessageId); echo $status->status, ' ', $status->deliveredAt?->format('d/m H:i');
Omni — filas, agentes e conversas
use WonitTecnologia\Interage\Enum\ConversationStatus; use WonitTecnologia\Interage\Request\TransferConversationRequest; $filas = $cli->omni->listQueues(); $agentes = $cli->omni->listAgents(); $conversas = $cli->omni->listConversations(status: ConversationStatus::Queue, channelType: 'whatsapp'); $historico = $cli->omni->getConversationHistory('<protocolo>', pageSize: 50); $cli->omni->transferConversation('<protocolo>', TransferConversationRequest::toQueue(3)); $cli->omni->transferConversation('<protocolo>', TransferConversationRequest::toUser('<user_id>')); $cli->omni->closeConversation('<protocolo>'); // Arquivo de uma mensagem do histórico (id da mensagem) $link = $cli->omni->createMessageFileTempLink($historico->items[0]->id, 3600); echo $link->url;
Contacts — central de contatos
$pagina = $cli->contacts->list(search: 'joão', pageSize: 20); $contato = $cli->contacts->get('<contact_uuid>'); $contato = $cli->contacts->getByPhone('5547999999999'); // NotFoundException se não existir
Criar contatos em lote
Até 500 contatos por chamada. Cada item é processado de forma independente — o erro de um não impede os demais.
use WonitTecnologia\Interage\Enum\CollisionPolicy; use WonitTecnologia\Interage\Request\BatchContactItem; use WonitTecnologia\Interage\Request\BatchCreateContactsRequest; use WonitTecnologia\Interage\Request\ContactIdentityInput; $resultado = $cli->contacts->batchCreate(new BatchCreateContactsRequest( contacts: [ new BatchContactItem( name: 'João da Silva', identities: [ContactIdentityInput::whatsapp('5511999998888', isPrimary: true)], email: 'joao@empresa.com', customInfo: ['codigo_cliente' => 'C-123'], labels: [1, 3], // números das etiquetas, não os nomes ), ], collisionPolicy: CollisionPolicy::Ignore, )); foreach ($resultado->items as $item) { if ($item->status === 'error') { echo "Contato #{$item->index}: {$item->message}", PHP_EOL; } }
labelsrecebe o número de cada etiqueta — o número sequencial exibido em Admin → Contatos → Etiquetas. A etiqueta precisa existir e estar ativa; senão o item falha e nada é gravado para aquele contato.customInfoaceita só texto: números e datas vão como string ('1990-05-20').- Limites por contato: nome 255 caracteres, CPF 14, e-mail/empresa 255, até 10
identidades, até 20 etiquetas,
customInfoaté 10 KB.
Telephony — ramais, histórico e click-to-call
use WonitTecnologia\Interage\Request\OriginateCallRequest; $ramais = $cli->telephony->listExtensions(search: '10'); $historico = $cli->telephony->listCallHistory( dateFrom: new DateTimeImmutable('2026-09-01'), dateTo: new DateTimeImmutable('2026-09-30'), // período de no máximo 3 meses callResult: 'ANSWERED', ); $ativas = $cli->telephony->listActiveCalls(); $chamada = $cli->telephony->originateCall(new OriginateCallRequest('1000', '5547999999999')); $gravacao = $cli->telephony->createRecordingTempLink('<call_id>', 3600);
Paginação
As listagens devolvem um Page com total, page, pageSize, items e nextCursor.
Campanhas, contatos e histórico de ligações também paginam por cursor, mais
indicado para percorrer listas grandes: passe o nextCursor como cursor da próxima
chamada. nextCursor é null na última página; com cursor informado, a API ignora page.
$cursor = null; do { $pagina = $cli->contacts->list(pageSize: 100, cursor: $cursor); foreach ($pagina->items as $contato) { echo $contato->name, PHP_EOL; } $cursor = $pagina->nextCursor; } while ($cursor !== null);
Tratamento de erros
Toda exceção do SDK implementa WonitTecnologia\Interage\Exception\InterageException.
Erros HTTP viram uma subclasse de ApiException, com $statusCode, $apiStatus,
$apiMessage e $retryAfter.
| Exceção | Quando |
|---|---|
BadRequestException |
400 — parâmetros inválidos |
UnauthorizedException |
401 — token ausente, inválido, expirado ou revogado |
ForbiddenException |
403 — token sem a rota ou sem a ação (libere no painel) |
NotFoundException |
404 — recurso não encontrado |
ConflictException |
409 — conflito de estado (ex.: ramal já em chamada) |
UnprocessableEntityException |
422 — ação não permitida no estado atual |
TooManyRequestsException |
429 — limite de requisições excedido |
ServerException |
5xx — erro da API; 503 é falha temporária, vale tentar de novo |
TransportException |
falha de rede/conexão, sem resposta da API |
ValidationException |
parâmetro inválido detectado pelo SDK, antes de chamar a API |
UnexpectedResponseException |
resposta de sucesso em formato inesperado |
use WonitTecnologia\Interage\Exception\ApiException; use WonitTecnologia\Interage\Exception\ForbiddenException; use WonitTecnologia\Interage\Exception\NotFoundException; use WonitTecnologia\Interage\Exception\TooManyRequestsException; try { $campanha = $cli->campaigns->get($id); } catch (NotFoundException) { // campanha não existe } catch (ForbiddenException $e) { // token válido, mas sem permissão para esta rota/ação } catch (TooManyRequestsException $e) { sleep($e->retryAfter ?? 1); $campanha = $cli->campaigns->get($id); } catch (ApiException $e) { error_log("{$e->statusCode} {$e->apiStatus}: {$e->apiMessage}"); }
O SDK não repete requisições sozinho — a decisão de esperar e tentar de novo fica com
quem chama. 401 é sempre a credencial: repetir com o mesmo token não resolve, e um IP
que acumula 20 respostas 401 em um minuto passa a receber 429 até a janela fechar —
exceto para tokens que autenticaram nos últimos 10 minutos, que seguem funcionando.
Testes
composer install
composer test
Licença
MIT — ver LICENSE.