diff --git a/docs/api/djmonitor.md b/docs/api/djmonitor.md new file mode 100644 index 0000000..373d244 --- /dev/null +++ b/docs/api/djmonitor.md @@ -0,0 +1,18 @@ +# Integração com DJMonitor + +## Configurações necessárias no DJMonitor + +1. **Liberação de módulo**: Solicite ao setor financeiro a liberação do módulo TEF IP para o cliente em questão; +2. **Forma de aprovação**: Altere a forma de aprovação para TEF IP nas formas de pagamentos que serão utilizadas juntamente com o TEF IP conforme print abaixo: + +!!! warning "Atenção!" + Para a forma de pagamento PIX, é necessário estar configurado como “tipo pagto: 17 - dinâmico” e com o campo “CNPJ da instituição do pagamento” preenchido + +![Configuração da forma de pagamento no DJMonitor](../assets/images/screenshot-djmonitor-forma-pagto.png){ style="width: 420px; display: block; margin: 0 auto;"} + + +## Configurações necessárias no DJPDV + + +**Endereço IP:** A única configuração necessária no PDV é apontar o IP do TEF IP, essa configuração está disponível na aba T.E.F do PDV, conforme print abaixo: +![Configuração da forma de endereço no DJPDV](../assets/images/screenshot-pdv-endereco.png){ style="width: 420px; display: block; margin: 0 auto;"} diff --git a/docs/api/xpos.md b/docs/api/xpos.md new file mode 100644 index 0000000..ece89c8 --- /dev/null +++ b/docs/api/xpos.md @@ -0,0 +1,17 @@ +# Integração com Xpos + +## Configurações necessárias no Xpos + +1. **Habilitar módulo TEF IP**: Nas configurações do Xpos, acesse a aba “Módulos” e habilite o parâmetro “Módulo TEF IP”. + ![Parâmetro do módulo TEF IP no Xpos](../assets/images/screenshot-xpos-modulo.png){ style="width: 420px; display: block; margin: 0 auto;"} + +2. **Endereço IP**: Acesse a aba TEF IP e configure o IP do terminal TEF IP. + ![Configuração do TEF IP no Xpos](../assets/images/screenshot-xpos-parametros.png){ style="width: 420px; display: block; margin: 0 auto;"} + +3. **Tipo aprovação TEF**: Acesse a aba “Parâmetros de Vendas” e na seção “Parâmetros de pagamentos” habilite o parâmetro “Integração com TEF” e em seguida altere o tipo de aprovação para TEF IP. + ![Configuração do tipo de aprovação TEF no Xpos](../assets/images/screenshot-xpos-parametro-venda.png){ style="width: 420px; display: block; margin: 0 auto;"} + + +### Configuração Adicional (impressão) +- **Impressão**: Com esse parâmetro de impressão você consegue escolher se a impressão será realizada diretamente na maquininha (TEF IP) ou pelo próprio dispositivo (POS), como por exemplo um totem de autoatendimento que possui uma impressora própria. + ![Configuração do tipo de impressão no Xpos](../assets/images/screenshot-xpos-impressao.png){ style="width: 420px; display: block; margin: 0 auto;"} diff --git a/docs/assets/images/screenshot-djmonitor-forma-pagto.png b/docs/assets/images/screenshot-djmonitor-forma-pagto.png new file mode 100644 index 0000000..9efd5de Binary files /dev/null and b/docs/assets/images/screenshot-djmonitor-forma-pagto.png differ diff --git a/docs/assets/images/screenshot-pdv-endereco.png b/docs/assets/images/screenshot-pdv-endereco.png new file mode 100644 index 0000000..51fbe95 Binary files /dev/null and b/docs/assets/images/screenshot-pdv-endereco.png differ diff --git a/docs/assets/images/screenshot-xpos-impressao.png b/docs/assets/images/screenshot-xpos-impressao.png new file mode 100644 index 0000000..2f5d83d Binary files /dev/null and b/docs/assets/images/screenshot-xpos-impressao.png differ diff --git a/docs/assets/images/screenshot-xpos-modulo.png b/docs/assets/images/screenshot-xpos-modulo.png new file mode 100644 index 0000000..fefb143 Binary files /dev/null and b/docs/assets/images/screenshot-xpos-modulo.png differ diff --git a/docs/assets/images/screenshot-xpos-parametro-venda.png b/docs/assets/images/screenshot-xpos-parametro-venda.png new file mode 100644 index 0000000..e8d4443 Binary files /dev/null and b/docs/assets/images/screenshot-xpos-parametro-venda.png differ diff --git a/docs/assets/images/screenshot-xpos-parametros.png b/docs/assets/images/screenshot-xpos-parametros.png new file mode 100644 index 0000000..ffda392 Binary files /dev/null and b/docs/assets/images/screenshot-xpos-parametros.png differ diff --git a/docs/getting-started.md b/docs/getting-started.md index a9ccf7d..eea2237 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -7,6 +7,21 @@ Este guia leva você da instalação até a primeira resposta real do terminal d - **Hardware:** terminal Android compatível (Stone, Getnet ou Rede) **ou** computador com Windows 10 ou superior - **Rede local:** o PDV e o terminal devem estar na mesma rede (ou usar `localhost` quando o TEF IP rodar na mesma máquina) + +### No Terminal Adquirente (SmartPOS) + +1. **Conectividade**: O terminal deve estar na mesma rede Wi-Fi que o PDV. +2. **IP Estático**: Recomenda-se configurar um IP fixo para o terminal no roteador para evitar que o PDV perca a conexão. +3. **Apps de Apoio**: Garanta que as dependências externas listadas na tabela acima estejam instaladas e atualizadas. +4. **Permissões**: Ao abrir o TEF IP pela primeira vez, aceite todas as permissões de rede, telefone e armazenamento. + +### No Windows (Emulador) + +1. **Porta 9050**: Certifique-se de que a porta `9050` está aberta no Firewall do Windows para conexões de entrada. +2. **Basic Auth**: Configure o usuário e senha desejados no arquivo de configurações do app. +3. **Visual C++ Redistributable**: Pode ser necessário para a execução do app em algumas versões do Windows. + +--- ## Instalação ### Terminais Android (Adquirentes) diff --git a/docs/index.md b/docs/index.md index 664cae8..a04442b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,8 +2,23 @@ Aceite pagamentos com qualquer adquirente usando uma única API HTTP local. Instale no terminal e comece a processar. ---- +## O que você pode fazer +- **Pagamentos** — Crédito, débito, PIX, dinheiro, voucher, cartão-presente; parcelamento pelo lojista ou pela emissora. +- **Vendas** — Monte um carrinho com itens e adicione múltiplas formas de pagamento; finalize com uma chamada. +- **Estornos** — Consulte e reverta transações por `referenceId`. +- **Display** — Exiba textos, imagens, carrosséis ou QR codes na tela do terminal em tempo real. +- **Perguntas** — Colete dados do cliente direto no terminal: CPF/CNPJ, texto livre, lista de opções, e-mail, CEP e mais. +- **Impressão** — Imprima imagens, comprovantes personalizados, layouts ACBr ou cupons fiscais (XML/DANFE). +- **Logs e alertas** — Consulte logs, acompanhe eventos em tempo real e dispare notificações locais ao operador. +- **Status** — Monitore saúde, tempo de atividade e reinicie o app remotamente. + +Veja abaixo um pagamento sendo processado no emulador: + +![GIF do terminal processando pagamento manual](assets/gif/emulador-terminal-pagamento-manual.gif){ style="display: block; margin: 0 auto;" } + + +--- ## Como funciona ```mermaid @@ -25,22 +40,6 @@ Seu sistema faz chamadas HTTP para o TEF IP. O TEF IP se comunica com o hardware Você pode desenvolver e testar toda a integração sem nenhum terminal físico. [Clique aqui para saber como usar o emulador](emulator.md) -Veja abaixo um pagamento sendo processado no emulador: - -![GIF do terminal processando pagamento manual](assets/gif/emulador-terminal-pagamento-manual.gif){ style="display: block; margin: 0 auto;" } - ---- - -## O que você pode fazer - -- **Pagamentos** — Crédito, débito, PIX, dinheiro, voucher, cartão-presente; parcelamento pelo lojista ou pela emissora. -- **Vendas** — Monte um carrinho com itens e adicione múltiplas formas de pagamento; finalize com uma chamada. -- **Estornos** — Consulte e reverta transações por `referenceId`. -- **Display** — Exiba textos, imagens, carrosséis ou QR codes na tela do terminal em tempo real. -- **Perguntas** — Colete dados do cliente direto no terminal: CPF/CNPJ, texto livre, lista de opções, e-mail, CEP e mais. -- **Impressão** — Imprima imagens, comprovantes personalizados, layouts ACBr ou cupons fiscais (XML/DANFE). -- **Logs e alertas** — Consulte logs, acompanhe eventos em tempo real e dispare notificações locais ao operador. -- **Status** — Monitore saúde, tempo de atividade e reinicie o app remotamente. --- diff --git a/docs/suporte/versoes-requisitos.md b/docs/suporte/versoes-requisitos.md deleted file mode 100644 index 568d088..0000000 --- a/docs/suporte/versoes-requisitos.md +++ /dev/null @@ -1,40 +0,0 @@ -# Versões e Requisitos - -O TEF IP é distribuído em versões específicas para cada adquirente. Cada versão é otimizada para o hardware do adquirente correspondente. Escolher a versão correta é essencial para que a integração com o terminal funcione. - ---- - -## Versões Disponíveis - -| Adquirente | Hardware Alvo | Dependências Externas | -|------------|---------------|-----------------------| -| Stone | SmartPOS | App "Stone SDK" | -| Rede | SmartPOS | App "Pagamento Rede" | -| Getnet | SmartPOS | App "Global Payments" | -| Emulador | Windows / Android | Nenhuma (perfeito para testes) | - ---- - -## Requisitos de Instalação - -### No Terminal Adquirente (SmartPOS) - -1. **Conectividade**: O terminal deve estar na mesma rede Wi-Fi que o PDV. -2. **IP Estático**: Recomenda-se configurar um IP fixo para o terminal no roteador para evitar que o PDV perca a conexão. -3. **Apps de Apoio**: Garanta que as dependências externas listadas na tabela acima estejam instaladas e atualizadas. -4. **Permissões**: Ao abrir o TEF IP pela primeira vez, aceite todas as permissões de rede, telefone e armazenamento. - -### No Windows (Emulador) - -1. **Porta 9050**: Certifique-se de que a porta `9050` está aberta no Firewall do Windows para conexões de entrada. -2. **Basic Auth**: Configure o usuário e senha desejados no arquivo de configurações do app. -3. **Visual C++ Redistributable**: Pode ser necessário para a execução do app em algumas versões do Windows. - -!!! tip "Validação pós-instalação" - Depois da instalação, confirme o ambiente com `GET /status` em `http://localhost:9050/status`. Se a API responder, a porta, o serviço e a autenticação básica já estarão operacionais. - ---- - -## Como Identificar a Versão - -Ao abrir o aplicativo TEF IP, a versão e o adquirente configurado geralmente constam na tela "Sobre" ou no rodapé da tela inicial. Certifique-se de que o logotipo do adquirente no app corresponde ao terminal físico que você possui. diff --git a/docs/suporte/versoes.md b/docs/suporte/versoes.md new file mode 100644 index 0000000..ebf3ce4 --- /dev/null +++ b/docs/suporte/versoes.md @@ -0,0 +1,19 @@ +# Versões + +O TEF IP é distribuído em versões específicas para cada adquirente. Cada versão é otimizada para o hardware do adquirente correspondente. Escolher a versão correta é essencial para que a integração com o terminal funcione. + +--- + +## Versões Disponíveis + +| Adquirente | Hardware Alvo | Dependências Externas | +|------------|---------------|-----------------------| +| Stone | SmartPOS | App "Stone SDK" | +| Rede | SmartPOS | App "Pagamento Rede" | +| Getnet | SmartPOS | App "Global Payments" | +| Emulador | Windows / Android | Nenhuma (perfeito para testes) | + + +## Como Identificar a Versão + +Ao abrir o aplicativo TEF IP, a versão e o adquirente configurado geralmente constam na tela "Sobre" ou no rodapé da tela inicial. Certifique-se de que o logotipo do adquirente no app corresponde ao terminal físico que você possui. diff --git a/mkdocs.yml b/mkdocs.yml index aee69a8..0d93958 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -67,6 +67,8 @@ nav: - Logs: api/logs.md - Notificações: api/notification.md - Especificação (Swagger): api/swagger.md + - Integração com DJMonitor: api/djmonitor.md + - Integração com Xpos: api/xpos.md - SDKs: - Visão geral: sdks.md - Dart (Oficial): sdk-dart.md @@ -74,5 +76,5 @@ nav: - PHP: sdk-php.md - Ruby: sdk-ruby.md - Suporte e Operações: - - Versões e Requisitos: suporte/versoes-requisitos.md + - Versões: suporte/versoes.md - Resolução de Problemas: suporte/resolucao-de-problemas.md diff --git a/site/404.html b/site/404.html index a2414ce..d5b3ea9 100644 --- a/site/404.html +++ b/site/404.html @@ -1,1230 +1,1271 @@ - - - - - - - - - - - - - - - - - - - - TEF IP Docs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
-
- -
- - - - -
- + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+ +
+ +

404 - Not found

+ +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/api/ask/index.html b/site/api/ask/index.html index fe33ae9..65f379f 100644 --- a/site/api/ask/index.html +++ b/site/api/ask/index.html @@ -1,1470 +1,1516 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Coleta de Dados - TEF IP Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Pular para conteúdo + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
-
-
-
- - - - - - - - - -
- - - - - - - - - -
-
- - - -
-
-
- - - - - - -
-
-
- - - -
-
- -
-
- - - -
- -
- - - - - -

Perguntas (Ask)

-

Endpoints para exibir perguntas interativas na tela do terminal e coletar respostas do cliente — CPF, e-mail, texto livre, listas de opções e muito mais.

-
-

Autenticação

-

Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instalação).

-
-
-

Como funciona

-

A requisição HTTP fica aberta até o usuário confirmar ou cancelar no terminal — ou o PDV enviar POST /ask/cancel. Use Pergunta Única (/ask) para campos avulsos e Formulário (/ask/form) para coletar vários campos em sequência; as respostas chegam todas juntas ao final.

-
-

Timeout

-

Configure o timeout do cliente para pelo menos 60 segundos, pois a resposta depende da interação humana no terminal.

-
-
-

POST /ask

-

Exibe uma única pergunta na tela do terminal e aguarda a resposta do cliente.

-

Corpo da requisição

- +
+
+ + + +
+ +
+ + + + + +

Perguntas (Ask)

+

Endpoints para exibir perguntas interativas na tela do terminal e coletar respostas do cliente — CPF, + e-mail, texto livre, listas de opções e muito mais.

+
+

Autenticação

+

Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / + senha definida na instalação).

+
+
+

Como funciona

+

A requisição HTTP fica aberta até o usuário confirmar ou cancelar no terminal — ou o PDV + enviar POST /ask/cancel. Use Pergunta Única (/ask) para campos + avulsos e Formulário (/ask/form) para coletar vários campos em sequência; as + respostas chegam todas juntas ao final.

+
+

Timeout

+

Configure o timeout do cliente para pelo menos 60 segundos, pois a resposta depende da + interação humana no terminal.

+
+
+

POST /ask

+

Exibe uma única pergunta na tela do terminal e aguarda a resposta do cliente.

+

Corpo da requisição

+
+
{
   "parameters": {
     "buttonText": "Confirmar",
     "showCancelButton": false,
@@ -1488,282 +1534,298 @@ 

POST /ask

"options": null } } -
-

Campos de parameters

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CampoTipoPadrãoDescrição
buttonTextstring"Confirmar"Texto do botão de confirmação
showCancelButtonboolfalseExibe botão de cancelamento
buttonCancelTextstring"Cancelar"Texto do botão de cancelamento
showSuccessMessageboolfalseExibe tela de sucesso após confirmação
successMessagestringnullMensagem de sucesso personalizada
successMessageIntervalint3000Duração (ms) da tela de sucesso
confirmAnswerboolfalseExige confirmação antes de submeter a resposta
-

Campos de question

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CampoTipoPadrãoDescrição
idint0Identificador da pergunta
questionstringnullTexto exibido na tela (se null, usa prompt padrão do tipo)
typestring"TEXT"Tipo de entrada (ver tabela abaixo)
requiredboolfalseResposta obrigatória
minLengthint0Comprimento mínimo da resposta
maxLengthint255Comprimento máximo da resposta
defaultValuestringnullValor pré-preenchido no campo
maskstringnullMáscara de entrada (ex.: "###.###.###-##")
regexstringnullRegex de validação personalizado
errorMessagestringnullMensagem de erro quando a validação falha
optionsarraynullOpções selecionáveis (obrigatório para LIST e BUTTON)
-

Tipos de entrada (type)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ValorDescrição
"TEXT"Texto livre
"NUMBER"Somente números
"PHONE"Número de telefone
"CPF"CPF (com validação)
"CNPJ"CNPJ (com validação)
"CPFORCNPJ"CPF ou CNPJ
"EMAIL"E-mail (com validação)
"CEP"CEP (com validação)
"DATE"Data
"TIME"Hora
"MONEY"Valor monetário
"REGEX"Validação por regex personalizado
"LIST"Lista de opções (requer options)
"BUTTON"Botões de opção (requer options)
-

Formato de options (obrigatório para LIST e BUTTON)

-
[
+
+
+

Campos de parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CampoTipoPadrãoDescrição
buttonTextstring"Confirmar"Texto do botão de confirmação
showCancelButtonboolfalseExibe botão de cancelamento
buttonCancelTextstring"Cancelar"Texto do botão de cancelamento
showSuccessMessageboolfalseExibe tela de sucesso após confirmação
successMessagestringnullMensagem de sucesso personalizada
successMessageIntervalint3000Duração (ms) da tela de sucesso
confirmAnswerboolfalseExige confirmação antes de submeter a resposta
+

Campos de question

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CampoTipoPadrãoDescrição
idint0Identificador da pergunta
questionstringnullTexto exibido na tela (se null, usa prompt padrão do tipo)
typestring"TEXT"Tipo de entrada (ver tabela abaixo)
requiredboolfalseResposta obrigatória
minLengthint0Comprimento mínimo da resposta
maxLengthint255Comprimento máximo da resposta
defaultValuestringnullValor pré-preenchido no campo
maskstringnullMáscara de entrada (ex.: "###.###.###-##")
regexstringnullRegex de validação personalizado
errorMessagestringnullMensagem de erro quando a validação falha
optionsarraynullOpções selecionáveis (obrigatório para LIST e BUTTON)
+

Tipos de entrada (type)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ValorDescrição
"TEXT"Texto livre
"NUMBER"Somente números
"PHONE"Número de telefone
"CPF"CPF (com validação)
"CNPJ"CNPJ (com validação)
"CPFORCNPJ"CPF ou CNPJ
"EMAIL"E-mail (com validação)
"CEP"CEP (com validação)
"DATE"Data
"TIME"Hora
"MONEY"Valor monetário
"REGEX"Validação por regex personalizado
"LIST"Lista de opções (requer options)
"BUTTON"Botões de opção (requer options)
+

Formato de options (obrigatório para LIST e + BUTTON) +

+
+
[
   { "id": 1, "name": "Sim", "value": "sim" },
   { "id": 2, "name": "Não", "value": "nao" }
 ]
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
CampoTipoDescrição
idintIdentificador único da opção
namestringTexto exibido na tela
valuestringValor retornado quando a opção é selecionada
-

Resposta — 200

-
{
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
CampoTipoDescrição
idintIdentificador único da opção
namestringTexto exibido na tela
valuestringValor retornado quando a opção é selecionada
+

Resposta — 200

+
+
{
   "id": 0,
   "value": "12345678900"
 }
-
- - - - - - - - - - - - - - - - - - - - -
CampoTipoDescrição
idintIdentificador da pergunta respondida
valuestringResposta fornecida pelo cliente
-

Exemplos de integração

-
-
-
-
curl -u admin:1234 \
+
+
+ + + + + + + + + + + + + + + + + + + + +
CampoTipoDescrição
idintIdentificador da pergunta respondida
valuestringResposta fornecida pelo cliente
+

Exemplos de integração

+
+
+
+
+
+
curl -u admin:1234 \
      -H "Content-Type: application/json" \
      -X POST http://localhost:9050/ask \
      -d '{
        "parameters": { "buttonText": "Confirmar" },
        "question": { "type": "CPF", "question": "Informe seu CPF" }
      }'
-
-
-
-
// pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
+
+
+
+
+
+
// pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
 TefIP.baseUrl = 'http://localhost:9050';
 TefIP.username = 'admin';
 TefIP.password = '1234';
@@ -1777,10 +1839,12 @@ 

Exemplos de integração

), ); print(answer.value); -
-
-
-
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
+
+
+
+
+
+
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
 const res = await fetch('http://localhost:9050/ask', {
   method: 'POST',
   headers: {
@@ -1793,10 +1857,12 @@ 

Exemplos de integração

}), }); const data = await res.json(); -
-
-
-
<?php
+
+
+
+
+
+
<?php
 // TODO: pacote PHP ainda não criado — usando curl diretamente
 $ch = curl_init('http://localhost:9050/ask');
 curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
@@ -1809,10 +1875,12 @@ 

Exemplos de integração

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
-
-
-
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
+
+
+
+
+
+
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
 require 'net/http'
 require 'json'
 
@@ -1825,19 +1893,24 @@ 

Exemplos de integração

}.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
-
-
-
-
-

POST /ask/form

-

Exibe um formulário com múltiplas perguntas em sequência. O cliente responde cada uma antes de passar para a próxima.

-
-

IDs automáticos

-

Se todas as perguntas tiverem id: 0, o TEF IP atribui IDs sequenciais automaticamente (0, 1, 2…). Se quiser IDs personalizados, cada pergunta deve ter um id único — duplicatas retornam 400.

-
-

Corpo da requisição

-
{
+
+
+
+
+
+
+

POST /ask/form

+

Exibe um formulário com múltiplas perguntas em sequência. O cliente responde cada uma antes de passar + para a próxima.

+
+

IDs automáticos

+

Se todas as perguntas tiverem id: 0, o TEF IP atribui IDs sequenciais automaticamente (0, + 1, 2…). Se quiser IDs personalizados, cada pergunta deve ter um id único — duplicatas + retornam 400.

+
+

Corpo da requisição

+
+
{
   "parameters": {
     "buttonText": "Próximo",
     "showCancelButton": true,
@@ -1868,25 +1941,41 @@ 

POST /ask/form

} ] } -
-

Resposta — 200

-

Array com a resposta de cada pergunta, na mesma ordem.

-
[
+
+
+

Resposta — 200

+

Array com a resposta de cada pergunta, na mesma ordem.

+
+
[
   { "id": 1, "value": "João Silva" },
   { "id": 2, "value": "12345678900" },
   { "id": 3, "value": "pix" }
 ]
-
-

Resposta — 400

-

{ "code": 400, "message": "Nenhuma pergunta recebida" }
-
-
{ "code": 400, "message": "Existem perguntas com IDs duplicados no formulário" }
-

-

Exemplos de integração

-
-
-
-
curl -u admin:1234 \
+
+
+

Resposta — 400

+

+

+
{ "code": 400, "message": "Nenhuma pergunta recebida" }
+
+
+
+
{ "code": 400, "message": "Existem perguntas com IDs duplicados no formulário" }
+
+
+

+

Exemplos de integração

+
+
+
+
+
+
curl -u admin:1234 \
      -H "Content-Type: application/json" \
      -X POST http://localhost:9050/ask/form \
      -d '{
@@ -1896,10 +1985,12 @@ 

Exemplos de integração

{ "id": 2, "question": "CPF", "type": "CPF" } ] }' -
-
-
-
final answers = await TefIP.instance.askForm.post(
+
+
+
+
+
+
final answers = await TefIP.instance.askForm.post(
   form: AskFormRequestModel(
     parameters: AskParametersModel(buttonText: 'Próximo'),
     questions: [
@@ -1911,10 +2002,12 @@ 

Exemplos de integração

for (final a in answers) { print('${a.id}: ${a.value}'); } -
-
-
-
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
+
+
+
+
+
+
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
 const res = await fetch('http://localhost:9050/ask/form', {
   method: 'POST',
   headers: {
@@ -1930,10 +2023,12 @@ 

Exemplos de integração

}), }); const data = await res.json(); -
-
-
-
<?php
+
+
+
+
+
+
<?php
 // TODO: pacote PHP ainda não criado — usando curl diretamente
 $ch = curl_init('http://localhost:9050/ask/form');
 curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
@@ -1949,10 +2044,12 @@ 

Exemplos de integração

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
-
-
-
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
+
+
+
+
+
+
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
 require 'net/http'
 require 'json'
 
@@ -1968,33 +2065,47 @@ 

Exemplos de integração

}.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
-
-
-
-
-

POST /ask/cancel

-

Cancela a pergunta ou formulário em exibição no momento.

-

Não há corpo na requisição.

-

Resposta — 200

-
{
+
+
+
+
+
+
+

POST /ask/cancel

+

Cancela a pergunta ou formulário em exibição no momento.

+

Não há corpo na requisição.

+

Resposta — 200

+
+
{
   "message": "Pergunta cancelada com sucesso"
 }
-
-

Exemplos de integração

-
-
-
-
curl -u admin:1234 \
+
+
+

Exemplos de integração

+
+
+
+
+
+
curl -u admin:1234 \
      -X POST http://localhost:9050/ask/cancel
-
-
-
-
await TefIP.instance.askCancel.post();
-
-
-
-
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
+
+
+
+
+
+
await TefIP.instance.askCancel.post();
+
+
+
+
+
+
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
 const res = await fetch('http://localhost:9050/ask/cancel', {
   method: 'POST',
   headers: {
@@ -2002,10 +2113,12 @@ 

Exemplos de integração

}, }); const data = await res.json(); -
-
-
-
<?php
+
+
+
+
+
+
<?php
 // TODO: pacote PHP ainda não criado — usando curl diretamente
 $ch = curl_init('http://localhost:9050/ask/cancel');
 curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
@@ -2013,10 +2126,12 @@ 

Exemplos de integração

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
-
-
-
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
+
+
+
+
+
+
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
 require 'net/http'
 require 'json'
 
@@ -2025,10 +2140,11 @@ 

Exemplos de integração

req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
-
-
-
+
+
+
+
+
@@ -2041,52 +2157,54 @@

Exemplos de integração

- - -
- - - - + - - - - - - -
-
-
- - - - - - - - - - - - - - +
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/api/display/index.html b/site/api/display/index.html index f57ac3f..08b4f3f 100644 --- a/site/api/display/index.html +++ b/site/api/display/index.html @@ -1,1620 +1,1682 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Visor do Terminal - TEF IP Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Pular para conteúdo + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
-
-
-
- - - - - - - - - -
- - - - - - - - - -
-
- - - -
-
-
- - - - - - -
-
-
- - - - - - - -
- -
- - - - - -

Display

-

Endpoints para controlar a tela do terminal — exibir imagens, textos formatados, carrosséis e limpar o display.

-
-

Autenticação

-

Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instalação).

-
-
-

Quando usar o display

-

O display é um canal independente do fluxo de pagamento — exibir conteúdo não bloqueia nem interfere com transações. Use-o para comunicação visual com o cliente:

-
    -
  • Antes do pagamento: exibir o valor total, promoção ou instruções de atendimento.
  • -
  • Durante a espera: o TEF IP assume o controle da tela ao processar um pagamento (QR Code do PIX, tela de inserção de cartão). Não envie comandos de display enquanto isBusy=true.
  • -
  • Após o pagamento: exibir confirmação, agradecimento ou próxima promoção.
  • -
  • Modo idle: exibir carrossel de imagens enquanto o terminal aguarda o próximo cliente.
  • -
-

Ao finalizar ou cancelar uma venda (POST /sale/finalize / POST /sale/cancel), o TEF IP limpa o display automaticamente.

-
-

POST /display/image

-

Exibe uma imagem em tela cheia na tela do terminal.

-

Corpo da requisição

-

Bytes binários da imagem, enviados diretamente no corpo da requisição.

- - - - - - - - - - - - - -
HeaderValor
Content-Typeapplication/octet-stream
-

Resposta — 200

-
{ "message": "Imagem exibida com sucesso" }
-
-

Resposta — 400 (nenhuma imagem enviada)

-
{ "code": 400, "message": "Nenhuma imagem enviada" }
-
-

Resposta — 500 (erro ao exibir)

-
{ "code": 500, "message": "Erro ao exibir imagem" }
-
-

Exemplos de integração

-
- + + + +
+ +
+ + + + + +

Display

+

Endpoints para controlar a tela do terminal — exibir imagens, textos formatados, carrosséis e limpar o + display.

+
+

Autenticação

+

Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / + senha definida na instalação).

+
+
+

Quando usar o display

+

O display é um canal independente do fluxo de pagamento — exibir conteúdo não bloqueia nem interfere com + transações. Use-o para comunicação visual com o cliente:

+
    +
  • Antes do pagamento: exibir o valor total, promoção ou instruções de atendimento.
  • +
  • Durante a espera: o TEF IP assume o controle da tela ao processar um pagamento (QR + Code do PIX, tela de inserção de cartão). Não envie comandos de display enquanto + isBusy=true. +
  • +
  • Após o pagamento: exibir confirmação, agradecimento ou próxima promoção.
  • +
  • Modo idle: exibir carrossel de imagens enquanto o terminal aguarda o próximo cliente. +
  • +
+

Ao finalizar ou cancelar uma venda (POST /sale/finalize / POST /sale/cancel), o + TEF IP limpa o display automaticamente.

+
+

POST /display/image

+

Exibe uma imagem em tela cheia na tela do terminal.

+

Corpo da requisição

+

Bytes binários da imagem, enviados diretamente no corpo da requisição.

+ + + + + + + + + + + + + +
HeaderValor
Content-Typeapplication/octet-stream
+

Resposta — 200

+
+
{ "message": "Imagem exibida com sucesso" }
+
+
+

Resposta — 400 (nenhuma imagem enviada)

+
+
{ "code": 400, "message": "Nenhuma imagem enviada" }
+
+
+

Resposta — 500 (erro ao exibir)

+
+
{ "code": 500, "message": "Erro ao exibir imagem" }
+
+
+

Exemplos de integração

+
+
+
+
+
+
curl -u admin:1234 \
      -H "Content-Type: application/octet-stream" \
      -X POST http://localhost:9050/display/image \
      --data-binary @imagem.png
-
-
-
-
// pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
+
+
+
+
+
+
// pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
 import 'dart:io';
 
 TefIP.baseUrl = 'http://localhost:9050';
@@ -1622,10 +1684,12 @@ 

Exemplos de integração

TefIP.password = '1234'; final imageData = await File('imagem.png').readAsBytes(); await TefIP.instance.displayImage.post(imageData: imageData); -
-
-
-
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
+
+
+
+
+
+
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
 const imageBytes = await fetch('/imagem.png').then(r => r.arrayBuffer());
 const res = await fetch('http://localhost:9050/display/image', {
   method: 'POST',
@@ -1636,10 +1700,12 @@ 

Exemplos de integração

body: imageBytes, }); const data = await res.json(); -
-
-
-
<?php
+
+
+
+
+
+
<?php
 // TODO: pacote PHP ainda não criado — usando curl diretamente
 $imageData = file_get_contents('imagem.png');
 $ch = curl_init('http://localhost:9050/display/image');
@@ -1650,10 +1716,12 @@ 

Exemplos de integração

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
-
-
-
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
+
+
+
+
+
+
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
 require 'net/http'
 require 'json'
 
@@ -1664,15 +1732,17 @@ 

Exemplos de integração

req.body = image_data res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
-
-
-
-
-

POST /display/text

-

Exibe conteúdo de texto formatado na tela do terminal.

-

Corpo da requisição

-
{
+
+
+
+
+
+
+

POST /display/text

+

Exibe conteúdo de texto formatado na tela do terminal.

+

Corpo da requisição

+
+
{
   "content": [
     { "text": { "value": "Bem-vindo!", "size": 24, "bold": true, "align": "center" } },
     { "line": { "divider": true } },
@@ -1681,65 +1751,75 @@ 

POST /display/text

"backgroundColor": "#FFFFFF", "showCloseButton": true } -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CampoTipoObrigatórioDescrição
contentarraySimInstruções de layout (ver formato abaixo)
backgroundColorstringNãoCor de fundo em hex (padrão: "#FFFFFF")
showCloseButtonboolNãoExibe botão para fechar a tela
-

Formato de content

-

Cada item do array é um objeto com uma chave identificando o tipo de elemento:

- - - - - - - - - - - - - - - - - -
TipoExemplo
Texto{ "text": { "value": "Olá", "size": 18, "bold": false, "align": "left" } }
Divisor{ "line": { "divider": true } }
-

Resposta — 200

-
{ "message": "Texto exibido com sucesso" }
-
-

Exemplos de integração

-
-
-
-
curl -u admin:1234 \
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CampoTipoObrigatórioDescrição
contentarraySimInstruções de layout (ver formato abaixo)
backgroundColorstringNãoCor de fundo em hex (padrão: "#FFFFFF")
showCloseButtonboolNãoExibe botão para fechar a tela
+

Formato de content

+

Cada item do array é um objeto com uma chave identificando o tipo de elemento:

+ + + + + + + + + + + + + + + + + +
TipoExemplo
Texto{ "text": { "value": "Olá", "size": 18, "bold": false, "align": "left" } }
Divisor{ "line": { "divider": true } }
+

Resposta — 200

+
+
{ "message": "Texto exibido com sucesso" }
+
+
+

Exemplos de integração

+
+
+
+
+
+
curl -u admin:1234 \
      -H "Content-Type: application/json" \
      -X POST http://localhost:9050/display/text \
      -d '{
@@ -1749,10 +1829,12 @@ 

Exemplos de integração

"backgroundColor": "#FFFFFF", "showCloseButton": true }' -
-
-
-
await TefIP.instance.displayText.post(
+
+
+
+
+
+
await TefIP.instance.displayText.post(
   displayTextRequest: DisplayTextRequestModel(
     content: [
       {'text': {'value': 'Bem-vindo!', 'size': 24, 'bold': true, 'align': 'center'}},
@@ -1761,10 +1843,12 @@ 

Exemplos de integração

showCloseButton: true, ), ); -
-
-
-
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
+
+
+
+
+
+
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
 const res = await fetch('http://localhost:9050/display/text', {
   method: 'POST',
   headers: {
@@ -1780,10 +1864,12 @@ 

Exemplos de integração

}), }); const data = await res.json(); -
-
-
-
<?php
+
+
+
+
+
+
<?php
 // TODO: pacote PHP ainda não criado — usando curl diretamente
 $ch = curl_init('http://localhost:9050/display/text');
 curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
@@ -1799,10 +1885,12 @@ 

Exemplos de integração

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
-
-
-
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
+
+
+
+
+
+
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
 require 'net/http'
 require 'json'
 
@@ -1818,15 +1906,18 @@ 

Exemplos de integração

}.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
-
-
-
-
-

POST /display/carousel

-

Exibe um carrossel de imagens na tela do terminal, alternando automaticamente em intervalos configuráveis.

-

Corpo da requisição

-
{
+
+
+
+
+
+
+

POST /display/carousel

+

Exibe um carrossel de imagens na tela do terminal, alternando automaticamente em intervalos + configuráveis.

+

Corpo da requisição

+
+
{
   "images": [
     "<base64 da imagem 1>",
     "<base64 da imagem 2>"
@@ -1836,80 +1927,90 @@ 

POST /display/carousel

"backgroundColor": "#000000", "showCloseButton": false } -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CampoTipoObrigatórioDescrição
imagesarray de stringSimImagens em Base64 (pelo menos uma)
intervalMsintNãoIntervalo entre imagens em ms (padrão: 3000)
transitionstringNãoAnimação de transição (padrão: "fade")
backgroundColorstringNãoCor de fundo em hex (padrão: "#FFFFFF")
showCloseButtonboolNãoExibe botão para fechar (padrão: false)
-

Valores de transition

- - - - - - - - - - - - - - - - - - - - - -
ValorDescrição
"fade"Transição por dissolução (padrão)
"slide"Transição por deslizamento
"none"Sem animação de transição
-

Resposta — 200

-
{ "message": "Carousel exibido com sucesso" }
-
-

Exemplos de integração

-
-
-
-
# Converta as imagens para Base64 antes de enviar
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CampoTipoObrigatórioDescrição
imagesarray de stringSimImagens em Base64 (pelo menos uma)
intervalMsintNãoIntervalo entre imagens em ms (padrão: 3000)
transitionstringNãoAnimação de transição (padrão: "fade")
backgroundColorstringNãoCor de fundo em hex (padrão: "#FFFFFF")
showCloseButtonboolNãoExibe botão para fechar (padrão: false)
+

Valores de transition

+ + + + + + + + + + + + + + + + + + + + + +
ValorDescrição
"fade"Transição por dissolução (padrão)
"slide"Transição por deslizamento
"none"Sem animação de transição
+

Resposta — 200

+
+
{ "message": "Carousel exibido com sucesso" }
+
+
+

Exemplos de integração

+
+
+
+
+
+
# Converta as imagens para Base64 antes de enviar
 IMG1=$(base64 -w 0 imagem1.png)
 IMG2=$(base64 -w 0 imagem2.png)
 
@@ -1917,10 +2018,12 @@ 

Exemplos de integração

-H "Content-Type: application/json" \ -X POST http://localhost:9050/display/carousel \ -d "{\"images\":[\"$IMG1\",\"$IMG2\"],\"intervalMs\":3000,\"transition\":\"fade\",\"backgroundColor\":\"#000000\"}" -
-
-
-
import 'dart:io';
+
+
+
+
+
+
import 'dart:io';
 
 final img1 = await File('imagem1.png').readAsBytes();
 final img2 = await File('imagem2.png').readAsBytes();
@@ -1932,10 +2035,12 @@ 

Exemplos de integração

backgroundColor: '#000000', ), ); -
-
-
-
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
+
+
+
+
+
+
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
 async function fileToBase64(file) {
   return new Promise((resolve) => {
     const reader = new FileReader();
@@ -1961,10 +2066,12 @@ 

Exemplos de integração

}), }); const data = await res.json(); -
-
-
-
<?php
+
+
+
+
+
+
<?php
 // TODO: pacote PHP ainda não criado — usando curl diretamente
 $img1 = base64_encode(file_get_contents('imagem1.png'));
 $img2 = base64_encode(file_get_contents('imagem2.png'));
@@ -1982,10 +2089,12 @@ 

Exemplos de integração

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
-
-
-
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
+
+
+
+
+
+
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
 require 'net/http'
 require 'json'
 require 'base64'
@@ -2004,31 +2113,45 @@ 

Exemplos de integração

}.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
-
-
-
-
-

POST /display/clear

-

Remove qualquer conteúdo exibido na tela do terminal e retorna ao estado padrão.

-

Não há corpo na requisição.

-

Resposta — 200

-
{ "message": "Display limpo com sucesso" }
-
-

Exemplos de integração

-
-
-
-
curl -u admin:1234 \
+
+
+
+
+
+
+

POST /display/clear

+

Remove qualquer conteúdo exibido na tela do terminal e retorna ao estado padrão.

+

Não há corpo na requisição.

+

Resposta — 200

+
+
{ "message": "Display limpo com sucesso" }
+
+
+

Exemplos de integração

+
+
+
+
+
+
curl -u admin:1234 \
      -X POST http://localhost:9050/display/clear
-
-
-
-
await TefIP.instance.displayClear.post();
-
-
-
-
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
+
+
+
+
+
+
await TefIP.instance.displayClear.post();
+
+
+
+
+
+
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
 const res = await fetch('http://localhost:9050/display/clear', {
   method: 'POST',
   headers: {
@@ -2036,10 +2159,12 @@ 

Exemplos de integração

}, }); const data = await res.json(); -
-
-
-
<?php
+
+
+
+
+
+
<?php
 // TODO: pacote PHP ainda não criado — usando curl diretamente
 $ch = curl_init('http://localhost:9050/display/clear');
 curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
@@ -2047,10 +2172,12 @@ 

Exemplos de integração

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
-
-
-
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
+
+
+
+
+
+
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
 require 'net/http'
 require 'json'
 
@@ -2059,31 +2186,46 @@ 

Exemplos de integração

req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
-
-
-
-
-

POST /display/pop

-

Fecha a sobreposição atualmente exibida na tela, voltando à tela anterior sem limpar o estado completo.

-

Não há corpo na requisição.

-

Resposta — 200

-
{ "message": "Display fechado com sucesso" }
-
-

Exemplos de integração

-
-
-
-
curl -u admin:1234 \
+
+
+
+
+
+
+

POST /display/pop

+

Fecha a sobreposição atualmente exibida na tela, voltando à tela anterior sem limpar o estado completo. +

+

Não há corpo na requisição.

+

Resposta — 200

+
+
{ "message": "Display fechado com sucesso" }
+
+
+

Exemplos de integração

+
+
+
+
+
+
curl -u admin:1234 \
      -X POST http://localhost:9050/display/pop
-
-
-
-
await TefIP.instance.displayPop.post();
-
-
-
-
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
+
+
+
+
+
+
await TefIP.instance.displayPop.post();
+
+
+
+
+
+
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
 const res = await fetch('http://localhost:9050/display/pop', {
   method: 'POST',
   headers: {
@@ -2091,10 +2233,12 @@ 

Exemplos de integração

}, }); const data = await res.json(); -
-
-
-
<?php
+
+
+
+
+
+
<?php
 // TODO: pacote PHP ainda não criado — usando curl diretamente
 $ch = curl_init('http://localhost:9050/display/pop');
 curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
@@ -2102,10 +2246,12 @@ 

Exemplos de integração

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
-
-
-
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
+
+
+
+
+
+
# TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
 require 'net/http'
 require 'json'
 
@@ -2114,10 +2260,11 @@ 

Exemplos de integração

req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
-
-
-
+
+
+
+
+
@@ -2130,52 +2277,54 @@

Exemplos de integração

- - -
- - - - + - - - - - - -
-
-
- - - - - - - - - - - - - - +
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/api/erros/index.html b/site/api/erros/index.html index 830c08a..00d26fa 100644 --- a/site/api/erros/index.html +++ b/site/api/erros/index.html @@ -1,1464 +1,1520 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - Visão Geral de Erros - TEF IP Docs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - Pular para conteúdo - - -
-
- -
- - - - -
- - -
- -
- - - - - - - - - -
-
- - - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  • - - - - - - - - - -
  • -
    -
    - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    - -
    - - -

    Códigos de Erro

    -

    O TEF IP utiliza códigos de status HTTP padrão para indicar o sucesso ou falha de uma requisição. Todas as respostas de erro acompanham um corpo JSON com detalhes adicionais.

    -

    Formato de Erro

    -
    {
    -  "code": 400,
    -  "message": "Mensagem descritiva do erro"
    -}
    -
    -
    -

    Tabela de Referência

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CódigoNomeSignificado para o Integrador
    200OKA operação foi processada com sucesso.
    204No ContentSucesso, mas não há conteúdo de retorno (ex.: respostas de CORS).
    400Bad RequestO corpo da requisição (JSON/XML/Binário) é inválido ou faltam campos obrigatórios.
    401UnauthorizedAs credenciais de Basic Auth estão ausentes ou incorretas.
    403ForbiddenA operação foi recusada pela adquirente ou as permissões são insuficientes (ex.: /restart em plataforma não-móvel).
    404Not FoundRecurso inexistente: venda, item, pagamento, desconto ou acréscimo não encontrado, ou nenhuma pergunta ativa em /ask/cancel.
    409ConflictVocê tentou iniciar uma operação que conflita com o estado atual (ex.: iniciar venda com outra aberta).
    499CancelledPergunta/formulário (/ask, /ask/form) cancelado pelo usuário ou via /ask/cancel.
    500Internal ErrorOcorreu um erro inesperado no servidor. Verifique os logs do dispositivo.
    503Service UnavailableO servidor está ocupado (isBusy) ou o aplicativo está em segundo plano (isActive = false).
    -
    -

    Sugestões de Tratamento

    -
      -
    • Tratamento de 503 (Ocupado): O PDV deve aguardar alguns segundos e tentar novamente (retry). Se o erro persistir por mais de 15 segundos com a mensagem de "Segundo Plano", avise o operador para abrir o app TEF IP na tela do terminal.
    • -
    • Tratamento de 409 (Conflito): Se receber 409 ao iniciar uma venda, o seu sistema deve perguntar ao operador se deseja "Recuperar" a venda em aberto ou "Cancelar" a anterior antes de prosseguir.
    • -
    • Tratamento de 401 (Não Autorizado): Verifique as configurações de usuário e senha no seu sistema e no terminal. Geralmente o padrão é admin / senha configurada.
    • -
    - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - + + + + + +
  • + + + + + Guia de Integração + + +
  • + + + + + + + + + + + + + +
  • + + + + + API Reference + + +
  • + + + + + + + + + + + +
  • + + + + + SDKs + + +
  • + + + + + + + + + + + +
  • + + + + + Suporte e Operações + + +
  • + + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + +

    Códigos de Erro

    +

    O TEF IP utiliza códigos de status HTTP padrão para indicar o sucesso ou falha de uma requisição. Todas + as respostas de erro acompanham um corpo JSON com detalhes adicionais.

    +

    Formato de Erro

    +
    +
    {
    +  "code": 400,
    +  "message": "Mensagem descritiva do erro"
    +}
    +
    +
    +
    +

    Tabela de Referência

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CódigoNomeSignificado para o Integrador
    200OKA operação foi processada com sucesso.
    204No ContentSucesso, mas não há conteúdo de retorno (ex.: respostas de CORS).
    400Bad RequestO corpo da requisição (JSON/XML/Binário) é inválido ou faltam campos obrigatórios.
    401UnauthorizedAs credenciais de Basic Auth estão ausentes ou incorretas.
    403ForbiddenA operação foi recusada pela adquirente ou as permissões são insuficientes (ex.: + /restart em plataforma não-móvel). +
    404Not FoundRecurso inexistente: venda, item, pagamento, desconto ou acréscimo não encontrado, ou nenhuma + pergunta ativa em /ask/cancel.
    409ConflictVocê tentou iniciar uma operação que conflita com o estado atual (ex.: iniciar venda com outra + aberta).
    499CancelledPergunta/formulário (/ask, /ask/form) cancelado pelo usuário ou via + /ask/cancel. +
    500Internal ErrorOcorreu um erro inesperado no servidor. Verifique os logs do dispositivo.
    503Service UnavailableO servidor está ocupado (isBusy) ou o aplicativo está em segundo plano + (isActive = false).
    +
    +

    Sugestões de Tratamento

    +
      +
    • Tratamento de 503 (Ocupado): O PDV deve aguardar alguns segundos e tentar novamente + (retry). Se o erro persistir por mais de 15 segundos com a mensagem de "Segundo Plano", avise o operador + para abrir o app TEF IP na tela do terminal.
    • +
    • Tratamento de 409 (Conflito): Se receber 409 ao iniciar uma venda, o seu sistema deve + perguntar ao operador se deseja "Recuperar" a venda em aberto ou "Cancelar" a anterior antes de + prosseguir.
    • +
    • Tratamento de 401 (Não Autorizado): Verifique as configurações de usuário e senha no + seu sistema e no terminal. Geralmente o padrão é admin / senha configurada.
    • +
    + + + + + + + + + + + + + +
    +
    + + + + + +
    + +
    + + + + +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/api/logs/index.html b/site/api/logs/index.html index 1adea76..b5b5335 100644 --- a/site/api/logs/index.html +++ b/site/api/logs/index.html @@ -1,1494 +1,1540 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Logs - TEF IP Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + Pular para conteúdo + + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    -
    -
    -
    - - - - - - - - - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    - -
    - - - - - -

    Logs

    -

    Endpoints para consultar, acompanhar em tempo real e exportar os logs do TEF IP. Eles ajudam a investigar falhas de integração, comportamento do servidor e eventos de roteamento HTTP.

    -
    -

    Autenticação

    -

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instalação).

    -
    -
    -

    Quando usar cada endpoint

    -

    Use GET /logs para análise pontual, GET /logs/stream para monitoramento em tempo real e GET /logs/zip/download quando precisar anexar os registros a um chamado ou auditoria.

    -
    -
    -

    GET /logs

    -

    Retorna uma lista de logs, com suporte a filtros por nível, origem, intervalo de datas e texto.

    -

    Query parameters

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ParâmetroTipoObrigatórioDescrição
    levelstringNãoNível do log: fatal, error, warning, info, trace, path, debug
    sourcestringNãoOrigem do log: app, router, http
    dateFromstringNãoData/hora inicial em ISO 8601
    dateTostringNãoData/hora final em ISO 8601
    limitintNãoNúmero máximo de registros retornados
    searchstringNãoBusca parcial em message e details
    -

    Resposta

    -
    [
    +                        GET /logs/zip/download
    +
    +                      
    +                    
    +
    +                    
    +
    +                  
    +
    +                  
  • + + + + GET /logs/stream + + + + + + +
  • + + + + +
    +
    +
    + + + +
    + +
    + + + + + +

    Logs

    +

    Endpoints para consultar, acompanhar em tempo real e exportar os logs do TEF IP. Eles ajudam a investigar + falhas de integração, comportamento do servidor e eventos de roteamento HTTP.

    +
    +

    Autenticação

    +

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / + senha definida na instalação).

    +
    +
    +

    Quando usar cada endpoint

    +

    Use GET /logs para análise pontual, GET /logs/stream para monitoramento em + tempo real e GET /logs/zip/download quando precisar anexar os registros a um chamado ou + auditoria.

    +
    +
    +

    GET /logs

    +

    Retorna uma lista de logs, com suporte a filtros por nível, origem, intervalo de datas e texto.

    +

    Query parameters

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ParâmetroTipoObrigatórioDescrição
    levelstringNãoNível do log: fatal, error, warning, info, + trace, path, debug +
    sourcestringNãoOrigem do log: app, router, http
    dateFromstringNãoData/hora inicial em ISO 8601
    dateTostringNãoData/hora final em ISO 8601
    limitintNãoNúmero máximo de registros retornados
    searchstringNãoBusca parcial em message e details
    +

    Resposta

    +
    +
    [
       {
         "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
         "level": "error",
    @@ -1498,58 +1544,68 @@ 

    GET /logs

    "createdAt": "2024-06-15T14:30:00.000Z" } ] -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoDescrição
    idstringIdentificador único do log
    levelstringSeveridade do evento
    sourcestringOrigem do log
    messagestringMensagem principal
    detailsstring | nullDetalhes adicionais, como stack trace ou payload
    createdAtstringData/hora em ISO 8601
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoDescrição
    idstringIdentificador único do log
    levelstringSeveridade do evento
    sourcestringOrigem do log
    messagestringMensagem principal
    detailsstring | nullDetalhes adicionais, como stack trace ou payload
    createdAtstringData/hora em ISO 8601
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          "http://localhost:9050/logs?level=error&source=http&limit=50&search=timeout"
    -
    -
    -
    -
    // pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
    +
    +
    +
    +
    +
    +
    // pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
     TefIP.baseUrl = 'http://localhost:9050';
     TefIP.username = 'admin';
     TefIP.password = '1234';
    @@ -1560,30 +1616,36 @@ 

    Exemplos de integração

    search: 'timeout', ); print(logs.first.message); -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/logs?level=error&source=http&limit=50&search=timeout', {
       headers: {
         'Authorization': 'Basic ' + btoa('admin:1234'),
       },
     });
     const data = await res.json();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/logs?level=error&source=http&limit=50&search=timeout');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
     $response = json_decode(curl_exec($ch), true);
     curl_close($ch);
    -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1592,65 +1654,80 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    GET /logs/zip/download

    -

    Exporta os logs filtrados como um arquivo ZIP. O arquivo retornado contém tefip_logs.log em texto plano.

    -

    Query parameters

    -

    Os mesmos filtros de GET /logs são aceitos, exceto search.

    -

    Resposta — 200

    - - - - - - - - - - - - - - - - - -
    HeaderValor
    Content-Typeapplication/zip
    Content-Dispositionattachment; filename="tefip_logs.zip"
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +
    +

    GET /logs/zip/download

    +

    Exporta os logs filtrados como um arquivo ZIP. O arquivo retornado contém tefip_logs.log em + texto plano.

    +

    Query parameters

    +

    Os mesmos filtros de GET /logs são aceitos, exceto search.

    +

    Resposta — 200

    + + + + + + + + + + + + + + + + + +
    HeaderValor
    Content-Typeapplication/zip
    Content-Dispositionattachment; filename="tefip_logs.zip"
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -o tefip_logs.zip \
          "http://localhost:9050/logs/zip/download?level=error&limit=200"
    -
    -
    -
    -
    import 'dart:io';
    +
    +
    +
    +
    +
    +
    import 'dart:io';
     
     final zipBytes = await TefIP.instance.log.downloadZip(
       level: TefIPLogLevel.error,
       limit: 200,
     );
     await File('tefip_logs.zip').writeAsBytes(zipBytes);
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/logs/zip/download?level=error&limit=200', {
       headers: {
         'Authorization': 'Basic ' + btoa('admin:1234'),
       },
     });
     const blob = await res.blob();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/logs/zip/download?level=error&limit=200');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -1658,10 +1735,12 @@ 

    Exemplos de integração

    $zipBytes = curl_exec($ch); curl_close($ch); file_put_contents('tefip_logs.zip', $zipBytes); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     
     uri = URI('http://localhost:9050/logs/zip/download?level=error&limit=200')
    @@ -1669,54 +1748,69 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } File.binwrite('tefip_logs.zip', res.body) -
    -
    -
    -
    -
    -

    GET /logs/stream

    -

    Abre uma conexão SSE (Server-Sent Events) e envia um novo evento para cada log gerado enquanto a conexão estiver aberta.

    -

    Resposta

    -
    data: {"id":"abc","level":"info","source":"http","message":"POST /transaction 200","details":null,"createdAt":"2024-06-15T14:30:00.000Z"}
    -
    - - - - - - - - - - - - - - - - - - - - - -
    HeaderValor
    Content-Typetext/event-stream
    Cache-Controlno-cache
    X-Accel-Bufferingno
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -N -u admin:1234 \
    +
    +
    +
    +
    +
    +
    +

    GET /logs/stream

    +

    Abre uma conexão SSE (Server-Sent Events) e envia um novo evento para cada log gerado enquanto a conexão + estiver aberta.

    +

    Resposta

    +
    +
    data: {"id":"abc","level":"info","source":"http","message":"POST /transaction 200","details":null,"createdAt":"2024-06-15T14:30:00.000Z"}
    +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    HeaderValor
    Content-Typetext/event-stream
    Cache-Controlno-cache
    X-Accel-Bufferingno
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -N -u admin:1234 \
          http://localhost:9050/logs/stream
    -
    -
    -
    -
    TefIP.instance.log.stream().listen((log) {
    +
    +
    +
    +
    +
    +
    TefIP.instance.log.stream().listen((log) {
       print('[${log.level.name}] ${log.message}');
     });
    -
    -
    -
    -
    // TODO: EventSource não permite definir Authorization; para browser, prefira um proxy autenticado
    +
    +
    +
    +
    +
    +
    // TODO: EventSource não permite definir Authorization; para browser, prefira um proxy autenticado
     const res = await fetch('http://localhost:9050/logs/stream', {
       headers: {
         'Authorization': 'Basic ' + btoa('admin:1234'),
    @@ -1731,10 +1825,12 @@ 

    Exemplos de integração

    if (done) break; console.log(decoder.decode(value, { stream: true })); } -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/logs/stream');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -1744,10 +1840,12 @@ 

    Exemplos de integração

    }); curl_exec($ch); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     
     uri = URI('http://localhost:9050/logs/stream')
    @@ -1761,10 +1859,11 @@ 

    Exemplos de integração

    end end end -
    -
    -
    -
    +
    +
    +
    +
    +
    @@ -1777,52 +1876,54 @@

    Exemplos de integração

    - - -
    - - - - + - - - - - - -
    -
    -
    - - - - - - - - - - - - - - +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/api/notification/index.html b/site/api/notification/index.html index e77c1b7..fd0916a 100644 --- a/site/api/notification/index.html +++ b/site/api/notification/index.html @@ -1,1384 +1,1440 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Notificações - TEF IP Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + Pular para conteúdo + + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    -
    -
    -
    - - - - - - - - - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - - - - - - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    - -
    - - - - - -

    Notificações

    -

    Endpoint para disparar uma notificação local no dispositivo que executa o TEF IP. É útil para chamar o operador de volta ao app ou sinalizar um evento importante no fluxo de pagamento.

    -
    -

    Autenticação

    -

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instalação).

    -
    -
    -

    Comportamento no Android

    -

    Em dispositivos Android, o TEF IP acorda a tela antes de exibir a notificação.

    -
    -
    -

    POST /notification

    -

    Envia uma notificação local com título e mensagem.

    -

    Corpo da requisição

    -
    {
    +              
    +            
    +
    +
    + + + +
    + +
    + + + + + +

    Notificações

    +

    Endpoint para disparar uma notificação local no dispositivo que executa o TEF IP. É útil para chamar o + operador de volta ao app ou sinalizar um evento importante no fluxo de pagamento.

    +
    +

    Autenticação

    +

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / + senha definida na instalação).

    +
    +
    +

    Comportamento no Android

    +

    Em dispositivos Android, o TEF IP acorda a tela antes de exibir a notificação.

    +
    +
    +

    POST /notification

    +

    Envia uma notificação local com título e mensagem.

    +

    Corpo da requisição

    +
    +
    {
       "title": "Novo pagamento",
       "message": "Restaure o aplicativo para processar"
     }
    -
    - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoObrigatórioDescrição
    titlestringSimTítulo da notificação
    messagestringSimCorpo da notificação
    -

    Resposta — 200

    -
    {
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoObrigatórioDescrição
    titlestringSimTítulo da notificação
    messagestringSimCorpo da notificação
    +

    Resposta — 200

    +
    +
    {
       "message": "Notificação enviada com sucesso"
     }
    -
    -

    Resposta — 400

    -
    {
    +
    +
    +

    Resposta — 400

    +
    +
    {
       "code": 400,
       "message": "Corpo da requisição inválido"
     }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X POST http://localhost:9050/notification \
          -d '{"title":"Novo pagamento","message":"Restaure o aplicativo para processar"}'
    -
    -
    -
    -
    // pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
    +
    +
    +
    +
    +
    +
    // pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
     TefIP.baseUrl = 'http://localhost:9050';
     TefIP.username = 'admin';
     TefIP.password = '1234';
    @@ -1388,10 +1444,12 @@ 

    Exemplos de integração

    message: 'Restaure o aplicativo para processar', ), ); -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/notification', {
       method: 'POST',
       headers: {
    @@ -1404,10 +1462,12 @@ 

    Exemplos de integração

    }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/notification');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -1420,10 +1480,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1436,10 +1498,11 @@ 

    Exemplos de integração

    }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    +
    +
    +
    +
    +
    @@ -1452,52 +1515,54 @@

    Exemplos de integração

    - - -
    - - - - + - - - - - - -
    -
    -
    - - - - - - - - - - - - - - +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/api/print/index.html b/site/api/print/index.html index 9b7f2e5..de63a31 100644 --- a/site/api/print/index.html +++ b/site/api/print/index.html @@ -1,1634 +1,1697 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Impressão - TEF IP Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + Pular para conteúdo + + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    -
    -
    -
    - - - - - - - - - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - -
    -
    -
    - - - - - - - -
    - -
    - - - - - -

    Impressão

    -

    Endpoints para imprimir imagens, comprovantes formatados e cupons fiscais (XML/DANFE) na impressora do terminal.

    -
    -

    Autenticação

    -

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instalação).

    -
    -
    -

    Bloqueio durante impressão

    -

    Todos os endpoints de impressão definem isBusy = true enquanto a operação está em andamento. Novas requisições que verificam o estado ocupado serão rejeitadas com 503.

    -
    -
    -

    Impressão Fiscal (DANFE/XML)

    -

    O TEF IP inclui um parser avançado para documentos fiscais eletrônicos. Ao invés de o seu sistema formatar o comprovante manualmente, você pode enviar o XML original da nota e o terminal cuidará da renderização.

    -

    Funcionamento do Parser

    -

    O servidor processa o XML e mapeia campos como: -* Dados do Emitente: Nome, CNPJ, Inscrição Estadual, Endereço. -* Dados do Destinatário: Nome/Razão Social, CPF/CNPJ. -* Itens: Descrição, quantidade, valor unitário e total. -* Totais: BC ICMS, Valor ICMS, Valor Total da Nota. -* Informações de Pagamento: Formas de pagamento utilizadas. -* Protocolo de Autorização: Número, data e hora da autorização.

    -

    Requisitos do XML

    -

    Para que a impressão ocorra sem erros, o XML deve: -1. Seguir o padrão nacional de NF-e/NFC-e (versão 4.00). -2. Estar completo e conter as tags de protocolo de autorização (<protNFe> ou <protCTe>). -3. Ser enviado com o header Content-Type: text/xml.

    -
    -

    Customização

    -

    Se precisar de um layout muito específico ou marcas próprias que não constam no XML, utilize o endpoint POST /print/text para montar o comprovante linha por linha.

    -
    -
    -

    POST /print/image

    -

    Imprime uma imagem diretamente na impressora do terminal.

    -

    Corpo da requisição

    -

    Bytes binários da imagem, enviados diretamente no corpo da requisição.

    - - - - - - - - - - - - - -
    HeaderValor
    Content-Typeapplication/octet-stream
    -

    Resposta — 200

    -
    { "message": "Impressão realizada com sucesso" }
    -
    -

    Resposta — 400 (nenhuma imagem enviada)

    -
    { "code": 400, "message": "Nenhuma imagem enviada" }
    -
    -

    Resposta — 500 (erro na impressão)

    -
    { "code": 500, "message": "Erro ao imprimir" }
    -
    -

    Exemplos de integração

    -
    - + + + +
    + +
    + + + + + +

    Impressão

    +

    Endpoints para imprimir imagens, comprovantes formatados e cupons fiscais (XML/DANFE) na impressora do + terminal.

    +
    +

    Autenticação

    +

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / + senha definida na instalação).

    +
    +
    +

    Bloqueio durante impressão

    +

    Todos os endpoints de impressão definem isBusy = true enquanto a operação está em + andamento. Novas requisições que verificam o estado ocupado serão rejeitadas com 503.

    +
    +
    +

    Impressão Fiscal (DANFE/XML)

    +

    O TEF IP inclui um parser avançado para documentos fiscais eletrônicos. Ao invés de o seu sistema + formatar o comprovante manualmente, você pode enviar o XML original da nota e o terminal cuidará da + renderização.

    +

    Funcionamento do Parser

    +

    O servidor processa o XML e mapeia campos como: + * Dados do Emitente: Nome, CNPJ, Inscrição Estadual, Endereço. + * Dados do Destinatário: Nome/Razão Social, CPF/CNPJ. + * Itens: Descrição, quantidade, valor unitário e total. + * Totais: BC ICMS, Valor ICMS, Valor Total da Nota. + * Informações de Pagamento: Formas de pagamento utilizadas. + * Protocolo de Autorização: Número, data e hora da autorização.

    +

    Requisitos do XML

    +

    Para que a impressão ocorra sem erros, o XML deve: + 1. Seguir o padrão nacional de NF-e/NFC-e (versão 4.00). + 2. Estar completo e conter as tags de protocolo de autorização (<protNFe> ou + <protCTe>). + 3. Ser enviado com o header Content-Type: text/xml. +

    +
    +

    Customização

    +

    Se precisar de um layout muito específico ou marcas próprias que não constam no XML, utilize o endpoint + POST /print/text para montar o comprovante linha por linha. +

    +
    +
    +

    POST /print/image

    +

    Imprime uma imagem diretamente na impressora do terminal.

    +

    Corpo da requisição

    +

    Bytes binários da imagem, enviados diretamente no corpo da requisição.

    + + + + + + + + + + + + + +
    HeaderValor
    Content-Typeapplication/octet-stream
    +

    Resposta — 200

    +
    +
    { "message": "Impressão realizada com sucesso" }
    +
    +
    +

    Resposta — 400 (nenhuma imagem enviada)

    +
    +
    { "code": 400, "message": "Nenhuma imagem enviada" }
    +
    +
    +

    Resposta — 500 (erro na impressão)

    +
    +
    { "code": 500, "message": "Erro ao imprimir" }
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/octet-stream" \
          -X POST http://localhost:9050/print/image \
          --data-binary @comprovante.png
    -
    -
    -
    -
    // pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
    +
    +
    +
    +
    +
    +
    // pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
     import 'dart:io';
     
     TefIP.baseUrl = 'http://localhost:9050';
    @@ -1636,10 +1699,12 @@ 

    Exemplos de integração

    TefIP.password = '1234'; final imageData = await File('comprovante.png').readAsBytes(); await TefIP.instance.printImage.post(imageData: imageData); -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const imageBytes = await fetch('/comprovante.png').then(r => r.arrayBuffer());
     const res = await fetch('http://localhost:9050/print/image', {
       method: 'POST',
    @@ -1650,10 +1715,12 @@ 

    Exemplos de integração

    body: imageBytes, }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $imageData = file_get_contents('comprovante.png');
     $ch = curl_init('http://localhost:9050/print/image');
    @@ -1664,10 +1731,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1678,15 +1747,18 @@ 

    Exemplos de integração

    req.body = image_data res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    POST /print/text

    -

    Imprime um comprovante com formatação personalizada. O corpo é um array JSON de instruções de impressão.

    -

    Corpo da requisição

    -
    [
    +
    +
    +
    +
    +
    +
    +

    POST /print/text

    +

    Imprime um comprovante com formatação personalizada. O corpo é um array JSON de instruções de impressão. +

    +

    Corpo da requisição

    +
    +
    [
       { "text": { "value": "COMPROVANTE", "size": 20, "bold": true,  "align": "center" } },
       { "line": { "divider": true } },
       { "text": { "value": "Produto: Coca-Cola",  "size": 14, "bold": false, "align": "left" } },
    @@ -1694,37 +1766,49 @@ 

    POST /print/text

    { "line": { "divider": true } }, { "text": { "value": "Obrigado pela compra!", "size": 14, "bold": false, "align": "center" } } ] -
    -

    Cada item do array define um elemento de impressão pela sua chave de tipo:

    - - - - - - - - - - - - - - - - - -
    TipoExemplo
    Texto{ "text": { "value": "...", "size": 16, "bold": false, "align": "left" } }
    Divisor{ "line": { "divider": true } }
    -

    Resposta — 200

    -
    { "message": "Impressão realizada com sucesso" }
    -
    -

    Resposta — 400 (nenhum conteúdo enviado)

    -
    { "code": 500, "message": "Nenhum texto enviado" }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +

    Cada item do array define um elemento de impressão pela sua chave de tipo:

    + + + + + + + + + + + + + + + + + +
    TipoExemplo
    Texto{ "text": { "value": "...", "size": 16, "bold": false, "align": "left" } }
    Divisor{ "line": { "divider": true } }
    +

    Resposta — 200

    +
    +
    { "message": "Impressão realizada com sucesso" }
    +
    +
    +

    Resposta — 400 (nenhum conteúdo enviado)

    +
    +
    { "code": 500, "message": "Nenhum texto enviado" }
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X POST http://localhost:9050/print/text \
          -d '[
    @@ -1732,20 +1816,24 @@ 

    Exemplos de integração

    {"line": {"divider": true}}, {"text": {"value": "Obrigado!", "size": 14, "bold": false, "align": "center"}} ]' -
    -
    -
    -
    await TefIP.instance.printText.post(
    +
    +
    +
    +
    +
    +
    await TefIP.instance.printText.post(
       text: [
         {'text': {'value': 'COMPROVANTE', 'size': 20, 'bold': true,  'align': 'center'}},
         {'line': {'divider': true}},
         {'text': {'value': 'Obrigado!',   'size': 14, 'bold': false, 'align': 'center'}},
       ],
     );
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/print/text', {
       method: 'POST',
       headers: {
    @@ -1759,10 +1847,12 @@ 

    Exemplos de integração

    ]), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/print/text');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -1776,10 +1866,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1793,62 +1885,83 @@ 

    Exemplos de integração

    ].to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    POST /print/xml

    -

    Imprime um cupom fiscal a partir de um XML de NF-e/DANFE. O TEF IP faz o parse do XML e renderiza automaticamente o layout do cupom fiscal.

    -

    Corpo da requisição

    -

    String com o conteúdo do XML da NF-e.

    - - - - - - - - - - - - - -
    HeaderValor
    Content-Typetext/xml
    -
    <?xml version="1.0" encoding="UTF-8"?>
    +
    +
    +
    +
    +
    +
    +

    POST /print/xml

    +

    Imprime um cupom fiscal a partir de um XML de NF-e/DANFE. O TEF IP faz o parse do XML e renderiza + automaticamente o layout do cupom fiscal.

    +

    Corpo da requisição

    +

    String com o conteúdo do XML da NF-e.

    + + + + + + + + + + + + + +
    HeaderValor
    Content-Typetext/xml
    +
    +
    <?xml version="1.0" encoding="UTF-8"?>
     <nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00">
       ...
     </nfeProc>
    -
    -

    Resposta — 200

    -
    { "message": "Impressão realizada com sucesso" }
    -
    -

    Resposta — 400 (nenhum XML enviado)

    -
    { "code": 403, "message": "Nenhum XML enviado" }
    -
    -

    Resposta — 500 (erro na impressão)

    -
    { "code": 500, "message": "Erro ao imprimir" }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +

    Resposta — 200

    +
    +
    { "message": "Impressão realizada com sucesso" }
    +
    +
    +

    Resposta — 400 (nenhum XML enviado)

    +
    +
    { "code": 403, "message": "Nenhum XML enviado" }
    +
    +
    +

    Resposta — 500 (erro na impressão)

    +
    +
    { "code": 500, "message": "Erro ao imprimir" }
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: text/xml" \
          -X POST http://localhost:9050/print/xml \
          --data-binary @nota-fiscal.xml
    -
    -
    -
    -
    import 'dart:io';
    +
    +
    +
    +
    +
    +
    import 'dart:io';
     
     final xml = await File('nota-fiscal.xml').readAsString();
     await TefIP.instance.printXml.post(xml: xml);
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const xml = await fetch('/nota-fiscal.xml').then(r => r.text());
     const res = await fetch('http://localhost:9050/print/xml', {
       method: 'POST',
    @@ -1859,10 +1972,12 @@ 

    Exemplos de integração

    body: xml, }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $xml = file_get_contents('nota-fiscal.xml');
     $ch = curl_init('http://localhost:9050/print/xml');
    @@ -1873,10 +1988,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1887,77 +2004,102 @@ 

    Exemplos de integração

    req.body = xml res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    POST /print/acbr

    -

    Imprime um layout descrito no formato de tags ACBr — texto puro enviado diretamente no corpo da requisição (sem JSON). Útil para reaproveitar layouts de PDV já escritos nesse padrão.

    -

    Corpo da requisição

    -

    Texto puro com as tags ACBr.

    - - - - - - - - - - - - - -
    HeaderValor
    Content-Typetext/plain
    -

    Tags suportadas

    - - - - - - - - - - - - - - - - - - - - - -
    CategoriaTags
    Estilo<n> negrito · <i> itálico · <s> sublinhado · <in> invertido · <e> expandido · <c> condensado · <a> altura dupla
    Alinhamento</ce> centro · </ae> esquerda · </ad> direita
    Estrutura</zera> reset · </fn> fonte normal · </linha_simples> e </linha_dupla> divisórias · <qrcode>...</qrcode> QR Code
    -
    -

    Tags ignoradas

    -

    </corte_total>, </corte> e </logo> são aceitas, mas não produzem efeito no terminal.

    -
    -

    Resposta — 200

    -
    { "message": "Impressão realizada com sucesso" }
    -
    -

    Resposta — 400 (nenhum conteúdo enviado)

    -
    { "code": 400, "message": "Nenhum conteúdo enviado" }
    -
    -

    Resposta — 500 (erro na impressão)

    -
    { "code": 500, "message": "Erro ao imprimir" }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +
    +

    POST /print/acbr

    +

    Imprime um layout descrito no formato de tags ACBr — texto puro enviado diretamente no + corpo da requisição (sem JSON). Útil para reaproveitar layouts de PDV já escritos nesse padrão.

    +

    Corpo da requisição

    +

    Texto puro com as tags ACBr.

    + + + + + + + + + + + + + +
    HeaderValor
    Content-Typetext/plain
    +

    Tags suportadas

    + + + + + + + + + + + + + + + + + + + + + +
    CategoriaTags
    Estilo<n> negrito · <i> itálico · <s> + sublinhado · <in> invertido · <e> expandido · + <c> condensado · <a> altura dupla +
    Alinhamento</ce> centro · </ae> esquerda · </ad> + direita
    Estrutura</zera> reset · </fn> fonte normal · + </linha_simples> e </linha_dupla> divisórias · + <qrcode>...</qrcode> QR Code +
    +
    +

    Tags ignoradas

    +

    </corte_total>, </corte> e </logo> são + aceitas, mas não produzem efeito no terminal.

    +
    +

    Resposta — 200

    +
    +
    { "message": "Impressão realizada com sucesso" }
    +
    +
    +

    Resposta — 400 (nenhum conteúdo enviado)

    +
    +
    { "code": 400, "message": "Nenhum conteúdo enviado" }
    +
    +
    +

    Resposta — 500 (erro na impressão)

    +
    +
    { "code": 500, "message": "Erro ao imprimir" }
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: text/plain" \
          -X POST http://localhost:9050/print/acbr \
          --data-binary $'</ce><n>TEF IP</n>\n</ae>Obrigado pela compra!\n</linha_simples>'
    -
    -
    -
    -
    // TODO: o SDK Dart ainda não expõe método para ACBr — usando http diretamente
    +
    +
    +
    +
    +
    +
    // TODO: o SDK Dart ainda não expõe método para ACBr — usando http diretamente
     import 'package:http/http.dart' as http;
     
     final layout = '</ce><n>TEF IP</n>\n</ae>Obrigado pela compra!\n</linha_simples>';
    @@ -1969,10 +2111,12 @@ 

    Exemplos de integração

    }, body: layout, ); -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const layout = '</ce><n>TEF IP</n>\n</ae>Obrigado pela compra!\n</linha_simples>';
     const res = await fetch('http://localhost:9050/print/acbr', {
       method: 'POST',
    @@ -1983,10 +2127,12 @@ 

    Exemplos de integração

    body: layout, }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $layout = "</ce><n>TEF IP</n>\n</ae>Obrigado pela compra!\n</linha_simples>";
     $ch = curl_init('http://localhost:9050/print/acbr');
    @@ -1997,10 +2143,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -2011,10 +2159,11 @@ 

    Exemplos de integração

    req.body = layout res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    +
    +
    +
    +
    +
    @@ -2027,52 +2176,54 @@

    Exemplos de integração

    - - -
    - - - - + - - - - - - -
    -
    -
    - - - - - - - - - - - - - - +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/api/sale/index.html b/site/api/sale/index.html index 1595b15..85df504 100644 --- a/site/api/sale/index.html +++ b/site/api/sale/index.html @@ -1,2485 +1,2534 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vendas - TEF IP Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + Pular para conteúdo + + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    -
    -
    - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    - -
    - - - - - -

    Venda

    -

    Endpoints para gerenciar vendas: abrir um carrinho, adicionar itens e pagamentos, e finalizar ou cancelar a venda. A venda organiza o que foi vendido — o pagamento financeiro é feito separadamente via POST /transaction.

    -
    -

    Autenticação

    -

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instalação).

    -
    -
    -

    Fluxo de venda

    -

    Uma venda segue a sequência: iniciaradicionar itensadicionar pagamentosfinalizar (ou cancelar). Apenas uma venda pode estar ativa por vez.

    -
    -
    -

    Ciclo de Vida da Venda

    -

    Diferente de uma transação avulsa, uma Venda no TEF IP é uma sessão que acumula itens e pagamentos antes de ser consolidada. O servidor gerencia o estado dessa venda internamente.

    -

    Fluxo de Estados

    -
    stateDiagram-v2
    +                        
    +
    +                      
    +                    
    +
    +                  
    +
    +                  
  • + + + + POST /sale/payment + + + + + + +
  • + +
  • + + + + PATCH /sale/payment/{paymentId} + + + + + + +
  • + +
  • + + + + DELETE /sale/payment/clear + + + + + + +
  • + +
  • + + + + DELETE /sale/payment/{paymentId} + + + + + + +
  • + +
  • + + + + Descontos da venda + + + + + + +
  • + +
  • + + + + Acréscimos da venda + + + + + + +
  • + +
  • + + + + POST /sale/finalize + + + + + + +
  • + +
  • + + + + POST /sale/cancel + + + + + + +
  • + + + + +
    +
    +
    + + + +
    + +
    + + + + + +

    Venda

    +

    Endpoints para gerenciar vendas: abrir um carrinho, adicionar itens e pagamentos, e finalizar ou cancelar + a venda. A venda organiza o que foi vendido — o pagamento financeiro é feito separadamente via + POST /transaction. +

    +
    +

    Autenticação

    +

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / + senha definida na instalação).

    +
    +
    +

    Fluxo de venda

    +

    Uma venda segue a sequência: iniciaradicionar itens → + adicionar pagamentosfinalizar (ou cancelar). + Apenas uma venda pode estar ativa por vez. +

    +
    +
    +

    Ciclo de Vida da Venda

    +

    Diferente de uma transação avulsa, uma Venda no TEF IP é uma sessão que acumula itens e + pagamentos antes de ser consolidada. O servidor gerencia o estado dessa venda internamente.

    +

    Fluxo de Estados

    +
    stateDiagram-v2
         [*] --> Aberta: POST /sale
         Aberta --> Aberta: itens (POST/PATCH/DELETE /sale/item · cancel · clear)
         Aberta --> Aberta: pagamentos (POST/PATCH/DELETE /sale/payment · clear)
    @@ -2489,24 +2538,37 @@ 

    Fluxo de Estados

    Aberta --> Cancelada: POST /sale/cancel Finalizada --> [*] Cancelada --> [*]
    -

    Regras Importantes

    -
      -
    1. Exclusividade: Apenas uma venda pode estar ativa por vez no dispositivo. Tentar iniciar uma nova sem encerrar a anterior resulta em erro 409 Conflict.
    2. -
    3. Sincronização: Operações de venda são síncronas. O servidor retorna a confirmação assim que o estado interno é atualizado.
    4. -
    5. Documento Fiscal: Os itens e pagamentos adicionados servem de base para a montagem de cupons fiscais e DANFE.
    6. -
    7. Pagamento financeiro: A venda registra o quê foi vendido e como foi pago — mas não processa o débito financeiro. O pagamento no cartão ou PIX é feito separadamente via POST /transaction. Finalize a venda após confirmar a aprovação da transação.
    8. -
    9. Limpeza: Ao finalizar ou cancelar, o TEF IP limpa automaticamente qualquer conteúdo que esteja sendo exibido no visor do terminal (pop de displays).
    10. -
    -
    -

    Forma das respostas

    -

    As rotas de venda seguem uma convenção consistente:

    -
      -
    • POST/PATCH de uma entidade (item, pagamento, desconto, acréscimo) retornam a própria entidade criada/atualizada.
    • -
    • DELETE/clear/cancel e as rotas de cabeçalho (GET/POST/PATCH /sale) retornam o cupom completo (SaleCoupon) — o estado atual da venda.
    • -
    • POST /sale/finalize e POST /sale/cancel retornam apenas { "message": "..." }.
    • -
    -

    O cupom completo (SaleCoupon) tem o seguinte formato:

    -
    {
    +            

    Regras Importantes

    +
      +
    1. Exclusividade: Apenas uma venda pode estar ativa por vez no dispositivo. Tentar + iniciar uma nova sem encerrar a anterior resulta em erro 409 Conflict.
    2. +
    3. Sincronização: Operações de venda são síncronas. O servidor retorna a confirmação + assim que o estado interno é atualizado.
    4. +
    5. Documento Fiscal: Os itens e pagamentos adicionados servem de base para a montagem de + cupons fiscais e DANFE.
    6. +
    7. Pagamento financeiro: A venda registra o quê foi vendido e + como foi pago — mas não processa o débito financeiro. O pagamento no + cartão ou PIX é feito separadamente via POST /transaction. + Finalize a venda após confirmar a aprovação da transação. +
    8. +
    9. Limpeza: Ao finalizar ou cancelar, o TEF IP limpa automaticamente qualquer conteúdo + que esteja sendo exibido no visor do terminal (pop de displays).
    10. +
    +
    +

    Forma das respostas

    +

    As rotas de venda seguem uma convenção consistente:

    +
      +
    • POST/PATCH de uma entidade (item, pagamento, desconto, + acréscimo) retornam a própria entidade criada/atualizada.
    • +
    • DELETE/clear/cancel e as rotas de cabeçalho + (GET/POST/PATCH /sale) retornam o cupom completo + (SaleCoupon) — o estado atual da venda.
    • +
    • POST /sale/finalize e POST /sale/cancel + retornam apenas { "message": "..." }.
    • +
    +

    O cupom completo (SaleCoupon) tem o seguinte formato:

    +
    +
    {
       "sale": {
         "customerDocument": "123.456.789-00",
         "customerName": "João Silva",
    @@ -2527,53 +2589,75 @@ 

    Forma das respostas

    "total": 0 } } -
    -
    -

    Valores monetários em reais

    -

    Todos os valores (unitPrice, total, value, discount, addition, etc.) trafegam em reais decimais (ex.: 10.50), não em centavos. Descontos e acréscimos são armazenados em módulo (valor absoluto): enviar -5.00 é equivalente a 5.00.

    -
    -
    -

    GET /sale

    -

    Retorna o estado da venda ativa (o cupom completo). Útil para sincronizar o carrinho a qualquer momento.

    -

    Resposta — 200

    -

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +

    Valores monetários em reais

    +

    Todos os valores (unitPrice, total, value, + discount, addition, etc.) trafegam em reais decimais (ex.: + 10.50), não em centavos. Descontos e acréscimos são armazenados em + módulo (valor absoluto): enviar -5.00 é equivalente a 5.00. +

    +
    +
    +

    GET /sale

    +

    Retorna o estado da venda ativa (o cupom completo). Útil para sincronizar o carrinho a qualquer momento. +

    +

    Resposta — 200

    +

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          http://localhost:9050/sale
    -
    -
    -
    -
    // pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
    +
    +
    +
    +
    +
    +
    // pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
     TefIP.baseUrl = 'http://localhost:9050';
     TefIP.username = 'admin';
     TefIP.password = '1234';
     final coupon = await TefIP.instance.sale.get();
     print('Total: ${coupon.summary.total}');
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale', {
       headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },
     });
     const data = await res.json();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
     $response = json_decode(curl_exec($ch), true);
     curl_close($ch);
    -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -2582,90 +2666,107 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    POST /sale

    -

    Inicia uma nova venda. Retorna 409 se já existir uma venda ativa.

    -

    Corpo da requisição

    -
    {
    +
    +
    +
    +
    +
    +
    +

    POST /sale

    +

    Inicia uma nova venda. Retorna 409 se já existir uma venda ativa.

    +

    Corpo da requisição

    +
    +
    {
       "customerDocument": "123.456.789-00",
       "customerName": "João Silva",
       "sellerName": "Maria",
       "additionalInfo": "Balcão 3"
     }
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoObrigatórioDescrição
    customerDocumentstringNãoCPF ou CNPJ do cliente
    customerNamestringNãoNome do cliente exibido no terminal
    sellerNamestringNãoNome do vendedor exibido no terminal
    additionalInfostringNãoInformação adicional exibida no terminal
    totalnumberNãoValor total a exibir na tela de venda
    -

    Resposta — 200

    -

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    -

    Resposta — 409 (já existe uma venda ativa)

    -
    { "code": 409, "message": "Já existe uma venda ativa!" }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoObrigatórioDescrição
    customerDocumentstringNãoCPF ou CNPJ do cliente
    customerNamestringNãoNome do cliente exibido no terminal
    sellerNamestringNãoNome do vendedor exibido no terminal
    additionalInfostringNãoInformação adicional exibida no terminal
    totalnumberNãoValor total a exibir na tela de venda
    +

    Resposta — 200

    +

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    +

    Resposta — 409 (já existe uma venda ativa)

    +
    +
    { "code": 409, "message": "Já existe uma venda ativa!" }
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X POST http://localhost:9050/sale \
          -d '{"customerName":"João Silva","sellerName":"Maria"}'
    -
    -
    -
    -
    final coupon = await TefIP.instance.sale.post(
    +
    +
    +
    +
    +
    +
    final coupon = await TefIP.instance.sale.post(
       request: SaleStartRequestModel(
         customerName: 'João Silva',
         sellerName: 'Maria',
       ),
     );
     print('Itens: ${coupon.items.length}');
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale', {
       method: 'POST',
       headers: {
    @@ -2675,10 +2776,12 @@ 

    Exemplos de integração

    body: JSON.stringify({ customerName: 'João Silva', sellerName: 'Maria' }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -2691,10 +2794,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -2704,33 +2809,48 @@ 

    Exemplos de integração

    req.body = { customerName: 'João Silva', sellerName: 'Maria' }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    PATCH /sale

    -

    Atualiza os dados da venda ativa (cliente, vendedor, informações adicionais). Usa o mesmo corpo que POST /sale.

    -

    Resposta — 200

    -

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +
    +

    PATCH /sale

    +

    Atualiza os dados da venda ativa (cliente, vendedor, informações adicionais). Usa o mesmo corpo que + POST /sale. +

    +

    Resposta — 200

    +

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X PATCH http://localhost:9050/sale \
          -d '{"customerName":"Maria Souza"}'
    -
    -
    -
    -
    await TefIP.instance.sale.patch(
    +
    +
    +
    +
    +
    +
    await TefIP.instance.sale.patch(
       request: SaleStartRequestModel(customerName: 'Maria Souza'),
     );
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale', {
       method: 'PATCH',
       headers: {
    @@ -2740,10 +2860,12 @@ 

    Exemplos de integração

    body: JSON.stringify({ customerName: 'Maria Souza' }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -2753,10 +2875,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -2766,38 +2890,54 @@ 

    Exemplos de integração

    req.body = { customerName: 'Maria Souza' }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    DELETE /sale/clear

    -

    Esvazia a venda ativa por completo — remove todos os itens, pagamentos, descontos e acréscimos, preservando o cabeçalho (cliente/vendedor).

    -

    Resposta — 200

    -

    Retorna o cupom completo (SaleCoupon) já esvaziado (ver Forma das respostas).

    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +
    +

    DELETE /sale/clear

    +

    Esvazia a venda ativa por completo — remove todos os itens, pagamentos, descontos e acréscimos, + preservando o cabeçalho (cliente/vendedor).

    +

    Resposta — 200

    +

    Retorna o cupom completo (SaleCoupon) já esvaziado (ver Forma das respostas).

    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -X DELETE http://localhost:9050/sale/clear
    -
    -
    -
    -
    await TefIP.instance.sale.clear();
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    await TefIP.instance.sale.clear();
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/clear', {
       method: 'DELETE',
       headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },
     });
     const data = await res.json();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/clear');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -2805,10 +2945,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -2817,15 +2959,17 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    POST /sale/item

    -

    Adiciona um item ao carrinho da venda ativa.

    -

    Corpo da requisição

    -
    {
    +
    +
    +
    +
    +
    +
    +

    POST /sale/item

    +

    Adiciona um item ao carrinho da venda ativa.

    +

    Corpo da requisição

    +
    +
    {
       "id": "item-001",
       "code": "7891234567890",
       "description": "Coca-Cola 350ml",
    @@ -2837,82 +2981,84 @@ 

    POST /sale/item

    "total": 9.50, "additionalInfo": null } -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoObrigatórioDescrição
    idstringSimIdentificador único do item
    codestringSimCódigo do produto (ex.: EAN/código de barras)
    descriptionstringSimDescrição exibida no terminal
    canceledboolNãoItem marcado como cancelado (padrão: false)
    quantitynumberSimQuantidade
    unitPricenumberSimPreço unitário (reais)
    discountnumberNãoDesconto aplicado ao item (módulo)
    additionnumberNãoAcréscimo aplicado ao item
    totalnumberSimValor total do item (reais)
    additionalInfostringNãoInformação adicional
    -

    Resposta — 200

    -

    Retorna o item criado (mesmo formato do corpo da requisição).

    -
    {
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoObrigatórioDescrição
    idstringSimIdentificador único do item
    codestringSimCódigo do produto (ex.: EAN/código de barras)
    descriptionstringSimDescrição exibida no terminal
    canceledboolNãoItem marcado como cancelado (padrão: false)
    quantitynumberSimQuantidade
    unitPricenumberSimPreço unitário (reais)
    discountnumberNãoDesconto aplicado ao item (módulo)
    additionnumberNãoAcréscimo aplicado ao item
    totalnumberSimValor total do item (reais)
    additionalInfostringNãoInformação adicional
    +

    Resposta — 200

    +

    Retorna o item criado (mesmo formato do corpo da requisição).

    +
    +
    {
       "id": "item-001",
       "code": "7891234567890",
       "description": "Coca-Cola 350ml",
    @@ -2924,22 +3070,34 @@ 

    POST /sale/item

    "total": 9.50, "additionalInfo": null } -
    -

    Resposta — 400 (item duplicado)

    -
    { "code": 400, "message": "Item já existente na venda!" }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +

    Resposta — 400 (item duplicado)

    +
    +
    { "code": 400, "message": "Item já existente na venda!" }
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X POST http://localhost:9050/sale/item \
          -d '{"id":"item-001","code":"7891234567890","description":"Coca-Cola 350ml","quantity":2,"unitPrice":5.00,"total":9.50}'
    -
    -
    -
    -
    final item = await TefIP.instance.saleItem.post(
    +
    +
    +
    +
    +
    +
    final item = await TefIP.instance.saleItem.post(
       item: SaleItemModel(
         id: 'item-001',
         code: '7891234567890',
    @@ -2950,10 +3108,12 @@ 

    Exemplos de integração

    ), ); print(item.id); -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/item', {
       method: 'POST',
       headers: {
    @@ -2970,10 +3130,12 @@ 

    Exemplos de integração

    }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/item');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -2990,10 +3152,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -3006,45 +3170,57 @@ 

    Exemplos de integração

    }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    PATCH /sale/item/{itemId}

    -

    Atualiza os dados de um item já adicionado à venda. O id no corpo é ignorado — o identificador vem do parâmetro de rota.

    -

    Parâmetros de rota

    - - - - - - - - - - - - - - - -
    ParâmetroTipoDescrição
    itemIdstringIdentificador do item a atualizar
    -

    Corpo igual ao de POST /sale/item. O id no corpo é ignorado — o identificador vem do parâmetro de rota.

    -

    Resposta — 200

    -

    Retorna o item atualizado (mesmo formato do corpo da requisição).

    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +
    +

    PATCH /sale/item/{itemId}

    +

    Atualiza os dados de um item já adicionado à venda. O id no corpo é ignorado — o + identificador vem do parâmetro de rota.

    +

    Parâmetros de rota

    + + + + + + + + + + + + + + + +
    ParâmetroTipoDescrição
    itemIdstringIdentificador do item a atualizar
    +

    Corpo igual ao de POST /sale/item. O id no corpo é ignorado — o identificador + vem do parâmetro de rota.

    +

    Resposta — 200

    +

    Retorna o item atualizado (mesmo formato do corpo da requisição).

    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X PATCH http://localhost:9050/sale/item/item-001 \
          -d '{"code":"7891234567890","description":"Coca-Cola 350ml","quantity":3,"unitPrice":5.00,"total":14.50}'
    -
    -
    -
    -
    await TefIP.instance.saleItem.patch(
    +
    +
    +
    +
    +
    +
    await TefIP.instance.saleItem.patch(
       itemId: 'item-001',
       item: SaleItemModel(
         code: '7891234567890',
    @@ -3054,10 +3230,12 @@ 

    Exemplos de integração

    total: 14.50, ), ); -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/item/item-001', {
       method: 'PATCH',
       headers: {
    @@ -3067,10 +3245,12 @@ 

    Exemplos de integração

    body: JSON.stringify({ code: '7891234567890', description: 'Coca-Cola 350ml', quantity: 3, unitPrice: 5.00, total: 14.50 }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/item/item-001');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -3083,10 +3263,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -3096,38 +3278,54 @@ 

    Exemplos de integração

    req.body = { code: '7891234567890', description: 'Coca-Cola 350ml', quantity: 3, unitPrice: 5.00, total: 14.50 }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    DELETE /sale/item/clear

    -

    Remove todos os itens da venda ativa, preservando pagamentos, descontos e acréscimos.

    -

    Resposta — 200

    -

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +
    +

    DELETE /sale/item/clear

    +

    Remove todos os itens da venda ativa, preservando pagamentos, descontos e acréscimos. +

    +

    Resposta — 200

    +

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -X DELETE http://localhost:9050/sale/item/clear
    -
    -
    -
    -
    await TefIP.instance.saleItem.clear();
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    await TefIP.instance.saleItem.clear();
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/item/clear', {
       method: 'DELETE',
       headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },
     });
     const data = await res.json();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/item/clear');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -3135,10 +3333,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -3147,62 +3347,80 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    DELETE /sale/item/{itemId}

    -

    Remove um item permanentemente do carrinho da venda ativa.

    -
    -

    Cancel vs Delete

    -
      -
    • DELETE /sale/item/{itemId} — remove o item do carrinho; não aparece mais na venda
    • -
    • POST /sale/item/{itemId}/cancel — mantém o item no carrinho mas o marca como cancelado (canceled: true); útil para manter o histórico de itens cancelados na nota fiscal ou comprovante
    • -
    -
    -

    Parâmetros de rota

    - - - - - - - - - - - - - - - -
    ParâmetroTipoDescrição
    itemIdstringIdentificador do item a remover
    -

    Resposta — 200

    -

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +
    +

    DELETE /sale/item/{itemId}

    +

    Remove um item permanentemente do carrinho da venda ativa.

    +
    +

    Cancel vs Delete

    +
      +
    • DELETE /sale/item/{itemId} — remove o item do carrinho; não aparece + mais na venda
    • +
    • POST /sale/item/{itemId}/cancel — mantém o item no carrinho mas o + marca como cancelado (canceled: true); útil para manter o histórico de itens cancelados + na nota fiscal ou comprovante
    • +
    +
    +

    Parâmetros de rota

    + + + + + + + + + + + + + + + +
    ParâmetroTipoDescrição
    itemIdstringIdentificador do item a remover
    +

    Resposta — 200

    +

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -X DELETE http://localhost:9050/sale/item/item-001
    -
    -
    -
    -
    await TefIP.instance.saleItem.delete(itemId: 'item-001');
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    await TefIP.instance.saleItem.delete(itemId: 'item-001');
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/item/item-001', {
       method: 'DELETE',
       headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },
     });
     const data = await res.json();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/item/item-001');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -3210,10 +3428,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -3222,55 +3442,71 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    POST /sale/item/{itemId}/cancel

    -

    Marca um item como cancelado sem removê-lo do carrinho. Útil para manter o histórico da venda.

    -

    Parâmetros de rota

    - - - - - - - - - - - - - - - -
    ParâmetroTipoDescrição
    itemIdstringIdentificador do item a cancelar
    -

    Resposta — 200

    -

    Retorna o cupom completo (SaleCoupon) com o item marcado como canceled: true (ver Forma das respostas).

    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +
    +

    POST /sale/item/{itemId}/cancel

    +

    Marca um item como cancelado sem removê-lo do carrinho. Útil para manter o histórico da venda.

    +

    Parâmetros de rota

    + + + + + + + + + + + + + + + +
    ParâmetroTipoDescrição
    itemIdstringIdentificador do item a cancelar
    +

    Resposta — 200

    +

    Retorna o cupom completo (SaleCoupon) com o item marcado como + canceled: true (ver Forma das respostas). +

    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -X POST http://localhost:9050/sale/item/item-001/cancel
    -
    -
    -
    -
    await TefIP.instance.saleItem.cancel(itemId: 'item-001');
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    await TefIP.instance.saleItem.cancel(itemId: 'item-001');
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/item/item-001/cancel', {
       method: 'POST',
       headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },
     });
     const data = await res.json();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/item/item-001/cancel');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -3278,10 +3514,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -3290,135 +3528,156 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    POST /sale/payment

    -

    Adiciona uma forma de pagamento à venda ativa.

    -

    Corpo da requisição

    -
    {
    +
    +
    +
    +
    +
    +
    +

    POST /sale/payment

    +

    Adiciona uma forma de pagamento à venda ativa.

    +

    Corpo da requisição

    +
    +
    {
       "id": "pgto-001",
       "tPag": "17",
       "description": null,
       "value": 50.00,
       "additionalInfo": null
     }
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoObrigatórioDescrição
    idstringSimIdentificador único do pagamento
    tPagstringNãoCódigo do tipo de pagamento (ver tabela abaixo; padrão "99")
    descriptionstringNãoDescrição exibida no terminal
    valuenumberSimValor do pagamento (reais)
    additionalInfostringNãoInformação adicional
    -

    Valores de tPag (código numérico — o mesmo código da adquirente)

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Código (tPag)Enum SDKDescrição
    "01"moneyDinheiro
    "03"creditCrédito
    "04"debitDébito
    "05"giftCartão-presente
    "17"pix · veroWalletPIX / Carteira digital Vero
    "99"unknown · voucher · adm · cancel · cancelDigitalWalletDemais tipos
    -
    -

    Envie o código numérico, não o nome

    -

    No JSON cru, tPag deve ser o código numérico ("17"), não o nome ("pix"). Um nome não reconhecido é interpretado como "99" (desconhecido). No SDK Dart, use o enum TefIPSalePaymentType.pix — ele converte para o código automaticamente.

    -
    -

    Resposta — 200

    -

    Retorna o pagamento criado (mesmo formato do corpo, com tPag numérico).

    -
    {
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoObrigatórioDescrição
    idstringSimIdentificador único do pagamento
    tPagstringNãoCódigo do tipo de pagamento (ver tabela abaixo; padrão "99")
    descriptionstringNãoDescrição exibida no terminal
    valuenumberSimValor do pagamento (reais)
    additionalInfostringNãoInformação adicional
    +

    Valores de tPag (código numérico — o mesmo código da adquirente)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Código (tPag)Enum SDKDescrição
    "01"moneyDinheiro
    "03"creditCrédito
    "04"debitDébito
    "05"giftCartão-presente
    "17"pix · veroWalletPIX / Carteira digital Vero
    "99"unknown · voucher · adm · cancel · + cancelDigitalWallet + Demais tipos
    +
    +

    Envie o código numérico, não o nome

    +

    No JSON cru, tPag deve ser o código numérico ("17"), não o + nome ("pix"). Um nome não reconhecido é interpretado como "99" (desconhecido). + No SDK Dart, use o enum TefIPSalePaymentType.pix — ele converte para o código + automaticamente.

    +
    +

    Resposta — 200

    +

    Retorna o pagamento criado (mesmo formato do corpo, com tPag numérico).

    +
    +
    {
       "id": "pgto-001",
       "tPag": "17",
       "description": null,
       "value": 50.00,
       "additionalInfo": null
     }
    -
    -

    Resposta — 400 (pagamento duplicado)

    -
    { "code": 400, "message": "Pagamento já existente na venda!" }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +

    Resposta — 400 (pagamento duplicado)

    +
    +
    { "code": 400, "message": "Pagamento já existente na venda!" }
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X POST http://localhost:9050/sale/payment \
          -d '{"id":"pgto-001","tPag":"17","value":50.00}'
    -
    -
    -
    -
    final payment = await TefIP.instance.salePayment.post(
    +
    +
    +
    +
    +
    +
    final payment = await TefIP.instance.salePayment.post(
       payment: SalePaymentModel(
         id: 'pgto-001',
         type: TefIPSalePaymentType.pix,
    @@ -3426,10 +3685,12 @@ 

    Exemplos de integração

    ), ); print(payment.id); -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/payment', {
       method: 'POST',
       headers: {
    @@ -3439,10 +3700,12 @@ 

    Exemplos de integração

    body: JSON.stringify({ id: 'pgto-001', tPag: '17', value: 50.00 }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/payment');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -3452,10 +3715,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -3465,55 +3730,68 @@ 

    Exemplos de integração

    req.body = { id: 'pgto-001', tPag: '17', value: 50.00 }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    PATCH /sale/payment/{paymentId}

    -

    Atualiza os dados de um pagamento já adicionado à venda.

    -

    Parâmetros de rota

    - - - - - - - - - - - - - - - -
    ParâmetroTipoDescrição
    paymentIdstringIdentificador do pagamento a atualizar
    -

    Corpo igual ao de POST /sale/payment. O id no corpo é ignorado — vem do parâmetro de rota.

    -

    Resposta — 200

    -

    Retorna o pagamento atualizado (com tPag numérico).

    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +
    +

    PATCH /sale/payment/{paymentId}

    +

    Atualiza os dados de um pagamento já adicionado à venda.

    +

    Parâmetros de rota

    + + + + + + + + + + + + + + + +
    ParâmetroTipoDescrição
    paymentIdstringIdentificador do pagamento a atualizar
    +

    Corpo igual ao de POST /sale/payment. O id no corpo é ignorado — vem do + parâmetro de rota.

    +

    Resposta — 200

    +

    Retorna o pagamento atualizado (com tPag numérico).

    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X PATCH http://localhost:9050/sale/payment/pgto-001 \
          -d '{"tPag":"03","value":50.00}'
    -
    -
    -
    -
    await TefIP.instance.salePayment.patch(
    +
    +
    +
    +
    +
    +
    await TefIP.instance.salePayment.patch(
       paymentId: 'pgto-001',
       payment: SalePaymentModel(
         type: TefIPSalePaymentType.credit,
         value: 50.00,
       ),
     );
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/payment/pgto-001', {
       method: 'PATCH',
       headers: {
    @@ -3523,10 +3801,12 @@ 

    Exemplos de integração

    body: JSON.stringify({ tPag: '03', value: 50.00 }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/payment/pgto-001');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -3536,10 +3816,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -3549,38 +3831,54 @@ 

    Exemplos de integração

    req.body = { tPag: '03', value: 50.00 }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    DELETE /sale/payment/clear

    -

    Remove todos os pagamentos da venda ativa, preservando itens, descontos e acréscimos.

    -

    Resposta — 200

    -

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +
    +

    DELETE /sale/payment/clear

    +

    Remove todos os pagamentos da venda ativa, preservando itens, descontos e acréscimos. +

    +

    Resposta — 200

    +

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -X DELETE http://localhost:9050/sale/payment/clear
    -
    -
    -
    -
    await TefIP.instance.salePayment.clear();
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    await TefIP.instance.salePayment.clear();
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/payment/clear', {
       method: 'DELETE',
       headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },
     });
     const data = await res.json();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/payment/clear');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -3588,10 +3886,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -3600,55 +3900,70 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    DELETE /sale/payment/{paymentId}

    -

    Remove uma forma de pagamento do carrinho da venda ativa.

    -

    Parâmetros de rota

    - - - - - - - - - - - - - - - -
    ParâmetroTipoDescrição
    paymentIdstringIdentificador do pagamento a remover
    -

    Resposta — 200

    -

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +
    +

    DELETE /sale/payment/{paymentId}

    +

    Remove uma forma de pagamento do carrinho da venda ativa.

    +

    Parâmetros de rota

    + + + + + + + + + + + + + + + +
    ParâmetroTipoDescrição
    paymentIdstringIdentificador do pagamento a remover
    +

    Resposta — 200

    +

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -X DELETE http://localhost:9050/sale/payment/pgto-001
    -
    -
    -
    -
    await TefIP.instance.salePayment.delete(paymentId: 'pgto-001');
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    await TefIP.instance.salePayment.delete(paymentId: 'pgto-001');
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/payment/pgto-001', {
       method: 'DELETE',
       headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },
     });
     const data = await res.json();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/payment/pgto-001');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -3656,10 +3971,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -3668,83 +3985,100 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    Descontos da venda

    -

    Descontos são valores subtraídos do total da venda, independentes dos descontos por item. Cada desconto tem um id próprio.

    -

    POST /sale/discount

    -

    Adiciona um desconto à venda ativa.

    -

    Corpo da requisição

    -
    {
    +
    +
    +
    +
    +
    +
    +

    Descontos da venda

    +

    Descontos são valores subtraídos do total da venda, independentes dos descontos por item. Cada desconto + tem um id próprio.

    +

    POST /sale/discount

    +

    Adiciona um desconto à venda ativa.

    +

    Corpo da requisição

    +
    +
    {
       "id": "desc-001",
       "description": "Cupom 10%",
       "value": 5.00,
       "additionalInfo": null
     }
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoObrigatórioDescrição
    idstringSimIdentificador único do desconto
    descriptionstringNãoDescrição exibida no terminal
    valuenumberSimValor do desconto em reais (armazenado em módulo)
    additionalInfostringNãoInformação adicional
    -

    Resposta — 200

    -

    Retorna o desconto criado (mesmo formato do corpo).

    -

    Resposta — 400 (desconto duplicado)

    -
    { "code": 400, "message": "Desconto já existente na venda!" }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoObrigatórioDescrição
    idstringSimIdentificador único do desconto
    descriptionstringNãoDescrição exibida no terminal
    valuenumberSimValor do desconto em reais (armazenado em módulo)
    additionalInfostringNãoInformação adicional
    +

    Resposta — 200

    +

    Retorna o desconto criado (mesmo formato do corpo).

    +

    Resposta — 400 (desconto duplicado)

    +
    +
    { "code": 400, "message": "Desconto já existente na venda!" }
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X POST http://localhost:9050/sale/discount \
          -d '{"id":"desc-001","description":"Cupom 10%","value":5.00}'
    -
    -
    -
    -
    final discount = await TefIP.instance.saleDiscount.post(
    +
    +
    +
    +
    +
    +
    final discount = await TefIP.instance.saleDiscount.post(
       discount: SaleDiscountModel(id: 'desc-001', description: 'Cupom 10%', value: 5.00),
     );
     print(discount.id);
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/discount', {
       method: 'POST',
       headers: {
    @@ -3754,10 +4088,12 @@ 

    Exemplos de integração

    body: JSON.stringify({ id: 'desc-001', description: 'Cupom 10%', value: 5.00 }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/discount');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -3769,10 +4105,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -3782,30 +4120,43 @@ 

    Exemplos de integração

    req.body = { id: 'desc-001', description: 'Cupom 10%', value: 5.00 }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -

    PATCH /sale/discount/{discountId}

    -

    Atualiza um desconto existente. O id no corpo é ignorado — vem do parâmetro de rota. Retorna o desconto atualizado.

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +

    PATCH /sale/discount/{discountId}

    +

    Atualiza um desconto existente. O id no corpo é ignorado — vem do parâmetro de rota. Retorna + o desconto atualizado.

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X PATCH http://localhost:9050/sale/discount/desc-001 \
          -d '{"value":7.50}'
    -
    -
    -
    -
    await TefIP.instance.saleDiscount.patch(
    +
    +
    +
    +
    +
    +
    await TefIP.instance.saleDiscount.patch(
       discountId: 'desc-001',
       discount: SaleDiscountModel(id: 'desc-001', value: 7.50),
     );
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/discount/desc-001', {
       method: 'PATCH',
       headers: {
    @@ -3815,10 +4166,12 @@ 

    PATCH /sale/discount/{discountId}

    body: JSON.stringify({ value: 7.50 }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/discount/desc-001');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -3828,10 +4181,12 @@ 

    PATCH /sale/discount/{discountId}

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -3841,34 +4196,52 @@ 

    PATCH /sale/discount/{discountId}

    req.body = { value: 7.50 }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -

    DELETE /sale/discount/{discountId} · DELETE /sale/discount/clear

    -

    DELETE /sale/discount/{discountId} remove um desconto; DELETE /sale/discount/clear remove todos. Ambos retornam o cupom completo (SaleCoupon, ver Forma das respostas).

    -
    -
    -
    -
    curl -u admin:1234 -X DELETE http://localhost:9050/sale/discount/desc-001
    +
    +
    +
    +
    +
    +

    DELETE /sale/discount/{discountId} · DELETE + /sale/discount/clear

    +

    DELETE /sale/discount/{discountId} remove um desconto; + DELETE /sale/discount/clear remove todos. Ambos retornam o cupom completo + (SaleCoupon, ver Forma das respostas). +

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 -X DELETE http://localhost:9050/sale/discount/desc-001
     curl -u admin:1234 -X DELETE http://localhost:9050/sale/discount/clear
    -
    -
    -
    -
    await TefIP.instance.saleDiscount.delete(discountId: 'desc-001');
    +
    +
    +
    +
    +
    +
    await TefIP.instance.saleDiscount.delete(discountId: 'desc-001');
     await TefIP.instance.saleDiscount.clear();
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     await fetch('http://localhost:9050/sale/discount/desc-001', {
       method: 'DELETE',
       headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },
     });
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/discount/desc-001');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -3876,10 +4249,12 @@ 

    DELETE /sale/dis curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -

    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -3888,83 +4263,100 @@ 

    DELETE /sale/dis req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -

    -
    -
    -
    -
    -

    Acréscimos da venda

    -

    Acréscimos são valores somados ao total da venda (ex.: taxa de serviço). Simétricos aos descontos, cada um com id próprio.

    -

    POST /sale/addition

    -

    Adiciona um acréscimo à venda ativa.

    -

    Corpo da requisição

    -
    {
    +
    +
    +
    +
    +
    +
    +

    Acréscimos da venda

    +

    Acréscimos são valores somados ao total da venda (ex.: taxa de serviço). Simétricos aos descontos, cada + um com id próprio.

    +

    POST /sale/addition

    +

    Adiciona um acréscimo à venda ativa.

    +

    Corpo da requisição

    +
    +
    {
       "id": "acrs-001",
       "description": "Taxa de serviço 10%",
       "value": 4.50,
       "additionalInfo": null
     }
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoObrigatórioDescrição
    idstringSimIdentificador único do acréscimo
    descriptionstringNãoDescrição exibida no terminal
    valuenumberSimValor do acréscimo em reais (armazenado em módulo)
    additionalInfostringNãoInformação adicional
    -

    Resposta — 200

    -

    Retorna o acréscimo criado (mesmo formato do corpo).

    -

    Resposta — 400 (acréscimo duplicado)

    -
    { "code": 400, "message": "Acréscimo já existente na venda!" }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoObrigatórioDescrição
    idstringSimIdentificador único do acréscimo
    descriptionstringNãoDescrição exibida no terminal
    valuenumberSimValor do acréscimo em reais (armazenado em módulo)
    additionalInfostringNãoInformação adicional
    +

    Resposta — 200

    +

    Retorna o acréscimo criado (mesmo formato do corpo).

    +

    Resposta — 400 (acréscimo duplicado)

    +
    +
    { "code": 400, "message": "Acréscimo já existente na venda!" }
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X POST http://localhost:9050/sale/addition \
          -d '{"id":"acrs-001","description":"Taxa de serviço 10%","value":4.50}'
    -
    -
    -
    -
    final addition = await TefIP.instance.saleAddition.post(
    +
    +
    +
    +
    +
    +
    final addition = await TefIP.instance.saleAddition.post(
       addition: SaleAdditionModel(id: 'acrs-001', description: 'Taxa de serviço 10%', value: 4.50),
     );
     print(addition.id);
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/addition', {
       method: 'POST',
       headers: {
    @@ -3974,10 +4366,12 @@ 

    Exemplos de integração

    body: JSON.stringify({ id: 'acrs-001', description: 'Taxa de serviço 10%', value: 4.50 }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/addition');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -3989,10 +4383,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -4002,30 +4398,43 @@ 

    Exemplos de integração

    req.body = { id: 'acrs-001', description: 'Taxa de serviço 10%', value: 4.50 }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -

    PATCH /sale/addition/{additionId}

    -

    Atualiza um acréscimo existente. O id no corpo é ignorado — vem do parâmetro de rota. Retorna o acréscimo atualizado.

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +

    PATCH /sale/addition/{additionId}

    +

    Atualiza um acréscimo existente. O id no corpo é ignorado — vem do parâmetro de rota. + Retorna o acréscimo atualizado.

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X PATCH http://localhost:9050/sale/addition/acrs-001 \
          -d '{"value":6.00}'
    -
    -
    -
    -
    await TefIP.instance.saleAddition.patch(
    +
    +
    +
    +
    +
    +
    await TefIP.instance.saleAddition.patch(
       additionId: 'acrs-001',
       addition: SaleAdditionModel(id: 'acrs-001', value: 6.00),
     );
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/addition/acrs-001', {
       method: 'PATCH',
       headers: {
    @@ -4035,10 +4444,12 @@ 

    PATCH /sale/addition/{additionId}

    body: JSON.stringify({ value: 6.00 }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/addition/acrs-001');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -4048,10 +4459,12 @@ 

    PATCH /sale/addition/{additionId}

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -4061,34 +4474,52 @@ 

    PATCH /sale/addition/{additionId}

    req.body = { value: 6.00 }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -

    DELETE /sale/addition/{additionId} · DELETE /sale/addition/clear

    -

    DELETE /sale/addition/{additionId} remove um acréscimo; DELETE /sale/addition/clear remove todos. Ambos retornam o cupom completo (SaleCoupon, ver Forma das respostas).

    -
    -
    -
    -
    curl -u admin:1234 -X DELETE http://localhost:9050/sale/addition/acrs-001
    +
    +
    +
    +
    +
    +

    DELETE /sale/addition/{additionId} · DELETE + /sale/addition/clear

    +

    DELETE /sale/addition/{additionId} remove um acréscimo; + DELETE /sale/addition/clear remove todos. Ambos retornam o cupom completo + (SaleCoupon, ver Forma das respostas). +

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 -X DELETE http://localhost:9050/sale/addition/acrs-001
     curl -u admin:1234 -X DELETE http://localhost:9050/sale/addition/clear
    -
    -
    -
    -
    await TefIP.instance.saleAddition.delete(additionId: 'acrs-001');
    +
    +
    +
    +
    +
    +
    await TefIP.instance.saleAddition.delete(additionId: 'acrs-001');
     await TefIP.instance.saleAddition.clear();
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     await fetch('http://localhost:9050/sale/addition/acrs-001', {
       method: 'DELETE',
       headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },
     });
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/addition/acrs-001');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -4096,10 +4527,12 @@ 

    DELETE /sale/add curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -

    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -4108,15 +4541,17 @@ 

    DELETE /sale/add req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -

    -
    -
    -
    -
    -

    POST /sale/finalize

    -

    Finaliza a venda ativa. Todos os itens e pagamentos adicionados são consolidados.

    -

    Corpo da requisição (opcional)

    -
    {
    +
    +
    +
    +
    +
    +
    +

    POST /sale/finalize

    +

    Finaliza a venda ativa. Todos os itens e pagamentos adicionados são consolidados.

    +

    Corpo da requisição (opcional)

    +
    +
    {
       "message": "Obrigado pela compra!",
       "showMessage": true,
       "showCloseButton": true,
    @@ -4124,76 +4559,90 @@ 

    POST /sale/finalize

    "buttonCloseText": "Fechar", "messageInterval": 3000 } -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoPadrãoDescrição
    messagestringnullMensagem exibida ao finalizar
    showMessagebooltrueExibe a mensagem de finalização
    showCloseButtonbooltrueExibe botão para fechar a tela
    showResultScreenbooltrueExibe a tela de resultado da venda
    buttonCloseTextstringnullTexto do botão fechar
    messageIntervalint3000Duração (ms) da mensagem exibida
    -

    Resposta — 200

    -
    { "message": "Venda finalizada com sucesso" }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoPadrãoDescrição
    messagestringnullMensagem exibida ao finalizar
    showMessagebooltrueExibe a mensagem de finalização
    showCloseButtonbooltrueExibe botão para fechar a tela
    showResultScreenbooltrueExibe a tela de resultado da venda
    buttonCloseTextstringnullTexto do botão fechar
    messageIntervalint3000Duração (ms) da mensagem exibida
    +

    Resposta — 200

    +
    +
    { "message": "Venda finalizada com sucesso" }
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X POST http://localhost:9050/sale/finalize \
          -d '{"message":"Obrigado pela compra!","showMessage":true}'
    -
    -
    -
    -
    await TefIP.instance.saleFinalize.post(
    +
    +
    +
    +
    +
    +
    await TefIP.instance.saleFinalize.post(
       params: SaleActionRequestModel(message: 'Obrigado pela compra!'),
     );
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/finalize', {
       method: 'POST',
       headers: {
    @@ -4203,10 +4652,12 @@ 

    Exemplos de integração

    body: JSON.stringify({ message: 'Obrigado pela compra!', showMessage: true }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/finalize');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -4216,10 +4667,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -4229,41 +4682,57 @@ 

    Exemplos de integração

    req.body = { message: 'Obrigado pela compra!', showMessage: true }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    POST /sale/cancel

    -

    Cancela a venda ativa e limpa o carrinho.

    -

    Corpo da requisição (opcional)

    -

    Mesmo formato de POST /sale/finalize.

    -

    Resposta — 200

    -
    { "message": "Venda cancelada com sucesso" }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +
    +
    +
    +
    +

    POST /sale/cancel

    +

    Cancela a venda ativa e limpa o carrinho.

    +

    Corpo da requisição (opcional)

    +

    Mesmo formato de POST /sale/finalize.

    +

    Resposta — 200

    +
    +
    { "message": "Venda cancelada com sucesso" }
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -X POST http://localhost:9050/sale/cancel
    -
    -
    -
    -
    await TefIP.instance.saleCancel.post();
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    await TefIP.instance.saleCancel.post();
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/sale/cancel', {
       method: 'POST',
       headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },
     });
     const data = await res.json();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/sale/cancel');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -4271,10 +4740,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -4283,10 +4754,11 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    +
    +
    +
    + + @@ -4299,52 +4771,54 @@

    Exemplos de integração

    - - - - - - - + - - - - - - -
    -
    -
    - - - - - - - - - - - - - - +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/api/status/index.html b/site/api/status/index.html index f626a31..cbfbf00 100644 --- a/site/api/status/index.html +++ b/site/api/status/index.html @@ -1,1515 +1,1576 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Status e Manutenção - TEF IP Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + Pular para conteúdo + + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    -
    -
    -
    - - - - - - - - - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    - -
    - - - - - -

    Status

    -

    Endpoints para monitorar a saúde do servidor TEF IP, consultar informações do dispositivo e reiniciar o aplicativo remotamente. Estes endpoints são sempre seguros de chamar — respondem mesmo durante pagamentos em andamento.

    -
    -

    Autenticação

    -

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instalação).

    -
    -
    -

    Disponíveis mesmo durante operações

    -

    GET /status, GET /info e POST /restart respondem normalmente mesmo quando há uma operação em andamento (isBusy=true). Use-os livremente para monitorar o estado do servidor sem risco de 503.

    -
    -
    -

    GET /status

    -

    Verifica se o servidor está no ar e retorna o tempo de atividade.

    -

    Resposta

    -
    {
    +                        GET /info
    +
    +                      
    +                    
    +
    +                    
    +
    +                  
    +
    +                  
  • + + + + POST /restart + + + + + + +
  • + + + + +
    +
    +
    + + + +
    + +
    + + + + + +

    Status

    +

    Endpoints para monitorar a saúde do servidor TEF IP, consultar informações do dispositivo e reiniciar o + aplicativo remotamente. Estes endpoints são sempre seguros de chamar — respondem mesmo durante pagamentos + em andamento.

    +
    +

    Autenticação

    +

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / + senha definida na instalação).

    +
    +
    +

    Disponíveis mesmo durante operações

    +

    GET /status, GET /info e POST /restart respondem normalmente + mesmo quando há uma operação em andamento (isBusy=true). Use-os livremente para monitorar o + estado do servidor sem risco de 503.

    +
    +
    +

    GET /status

    +

    Verifica se o servidor está no ar e retorna o tempo de atividade.

    +

    Resposta

    +
    +
    {
       "status": "ok",
       "uptimeSeconds": 144,
       "startedAt": "2026-01-28T16:20:53.223883"
     }
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoDescrição
    statusstringSempre "ok" quando o servidor responde
    uptimeSecondsintSegundos desde a inicialização do servidor
    startedAtstringData/hora de início em formato ISO 8601
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoDescrição
    statusstringSempre "ok" quando o servidor responde
    uptimeSecondsintSegundos desde a inicialização do servidor
    startedAtstringData/hora de início em formato ISO 8601
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          http://localhost:9050/status
    -
    -
    -
    -
    // pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
    +
    +
    +
    +
    +
    +
    // pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
     TefIP.baseUrl = 'http://localhost:9050';
     TefIP.username = 'admin';
     TefIP.password = '1234';
     final status = await TefIP.instance.status.get();
     print(status.uptimeSeconds);
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/status', {
       headers: {
         'Authorization': 'Basic ' + btoa('admin:1234'),
       },
     });
     const data = await res.json();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/status');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
     $response = json_decode(curl_exec($ch), true);
     curl_close($ch);
    -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1518,15 +1579,18 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    GET /info

    -

    Retorna informações detalhadas sobre o aplicativo e o dispositivo, incluindo o estado atual do servidor.

    -

    Resposta

    -
    {
    +
    +
    +
    +
    +
    +
    +

    GET /info

    +

    Retorna informações detalhadas sobre o aplicativo e o dispositivo, incluindo o estado atual do servidor. +

    +

    Resposta

    +
    +
    {
       "appName": "TEF IP",
       "version": "1.2.0",
       "build": "42",
    @@ -1537,106 +1601,126 @@ 

    GET /info

    "isActive": true, "isBusy": false } -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoDescrição
    appNamestringNome do aplicativo
    versionstringVersão semântica
    buildstringNúmero de build
    platformstringPlataforma do dispositivo (android, windows, etc.)
    localestringLocale configurado no dispositivo
    timeZonestringFuso horário do dispositivo
    modestringModo de operação (production, emulator)
    isActivebooltrue quando o app está em primeiro plano
    isBusybooltrue quando há uma operação em andamento (pagamento, impressão)
    -
    -

    Monitorando isBusy

    -

    Use isBusy para saber se o terminal está livre antes de enviar uma nova operação. Requisições enviadas enquanto isBusy é true serão rejeitadas com 503.

    -
    -
    -

    Saiba mais

    -

    Veja Comportamento → Servidor ocupado para entender como o servidor lida com operações simultâneas.

    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoDescrição
    appNamestringNome do aplicativo
    versionstringVersão semântica
    buildstringNúmero de build
    platformstringPlataforma do dispositivo (android, windows, etc.)
    localestringLocale configurado no dispositivo
    timeZonestringFuso horário do dispositivo
    modestringModo de operação (production, emulator)
    isActivebooltrue quando o app está em primeiro plano
    isBusybooltrue quando há uma operação em andamento (pagamento, impressão)
    +
    +

    Monitorando isBusy

    +

    Use isBusy para saber se o terminal está livre antes de enviar uma nova operação. + Requisições enviadas enquanto isBusy é true serão rejeitadas com + 503. +

    +
    +
    +

    Saiba mais

    +

    Veja Comportamento → Servidor ocupado para entender + como o servidor lida com operações simultâneas.

    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          http://localhost:9050/info
    -
    -
    -
    -
    final info = await TefIP.instance.info.get();
    +
    +
    +
    +
    +
    +
    final info = await TefIP.instance.info.get();
     print('${info.appName} v${info.version} — isBusy: ${info.isBusy}');
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/info', {
       headers: {
         'Authorization': 'Basic ' + btoa('admin:1234'),
       },
     });
     const data = await res.json();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/info');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
     $response = json_decode(curl_exec($ch), true);
     curl_close($ch);
    -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1645,46 +1729,63 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    POST /restart

    -

    Reinicia o aplicativo TEF IP remotamente. Disponível apenas em dispositivos móveis (Android ou iOS).

    -
    -

    Somente dispositivos móveis

    -

    Em plataformas não-móveis (Windows, emulador de desktop), este endpoint retorna 403.

    -
    -

    Resposta — 200

    -

    Mesma estrutura de GET /status, refletindo o estado após o reinício.

    -
    {
    +
    +
    +
    +
    +
    +
    +

    POST /restart

    +

    Reinicia o aplicativo TEF IP remotamente. Disponível apenas em dispositivos móveis (Android ou + iOS).

    +
    +

    Somente dispositivos móveis

    +

    Em plataformas não-móveis (Windows, emulador de desktop), este endpoint retorna 403.

    +
    +

    Resposta — 200

    +

    Mesma estrutura de GET /status, refletindo o estado após o reinício.

    +
    +
    {
       "status": "ok",
       "uptimeSeconds": 0,
       "startedAt": "2026-03-25T10:00:00.000000"
     }
    -
    -

    Resposta — 403

    -
    {
    +
    +
    +

    Resposta — 403

    +
    +
    {
       "code": 403,
       "message": "Reinicialização disponível apenas para dispositivos móveis"
     }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -X POST http://localhost:9050/restart
    -
    -
    -
    -
    final result = await TefIP.instance.restart.post();
    +
    +
    +
    +
    +
    +
    final result = await TefIP.instance.restart.post();
     print(result.status);
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/restart', {
       method: 'POST',
       headers: {
    @@ -1692,10 +1793,12 @@ 

    Exemplos de integração

    }, }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/restart');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -1703,10 +1806,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1715,10 +1820,11 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    +
    +
    +
    +
    +
    @@ -1731,52 +1837,54 @@

    Exemplos de integração

    - - -
    - - - - + - - - - - - -
    -
    -
    - - - - - - - - - - - - - - +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/api/swagger/index.html b/site/api/swagger/index.html index e76e275..bc48d3c 100644 --- a/site/api/swagger/index.html +++ b/site/api/swagger/index.html @@ -1,1380 +1,1426 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Especificação (Swagger) - TEF IP Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + Pular para conteúdo + + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    -
    -
    -
    - - - - - - - - - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    - -
    - - - - - -

    Swagger / OpenAPI

    -

    O TEF IP expõe uma interface Swagger UI interativa e o spec OpenAPI diretamente no terminal — sem necessidade de nenhuma ferramenta externa.

    -
    -

    Rotas públicas

    -

    Os endpoints /docs e /openapi.bundle.yaml não exigem autenticação e podem ser acessados diretamente no navegador.

    -
    -
    -

    GET /docs

    -

    Abre a interface Swagger UI no navegador. Permite explorar e testar todos os endpoints da API de forma interativa.

    -

    O spec é carregado automaticamente e os servidores disponíveis são detectados e listados em tempo real com base nas instâncias ativas do TEF IP na rede.

    -

    Como acessar:

    -

    Abra o navegador e acesse http://<ip-do-terminal>:9050/docs.

    -

    TODO: adicionar screenshot da Swagger UI do TEF IP

    -
    -

    GET /openapi.bundle.yaml

    -

    Retorna o spec OpenAPI completo em formato YAML. O spec inclui a lista de servidores detectados dinamicamente, incluindo o status de cada instância (Online/Offline).

    -

    Resposta — 200

    -
    openapi: 3.0.0
    +                        
    +
    +                        
  • + + + + Como importar no Insomnia + + + + +
  • + + + + + + + + + +
    +
    +
    + + + +
    + +
    + + + + + +

    Swagger / OpenAPI

    +

    O TEF IP expõe uma interface Swagger UI interativa e o spec OpenAPI diretamente no terminal — sem + necessidade de nenhuma ferramenta externa.

    +
    +

    Rotas públicas

    +

    Os endpoints /docs e /openapi.bundle.yaml não exigem + autenticação e podem ser acessados diretamente no navegador.

    +
    +
    +

    GET /docs

    +

    Abre a interface Swagger UI no navegador. Permite explorar e testar todos os endpoints da API de forma + interativa.

    +

    O spec é carregado automaticamente e os servidores disponíveis são detectados e listados em tempo real + com base nas instâncias ativas do TEF IP na rede.

    +

    Como acessar:

    +

    Abra o navegador e acesse http://<ip-do-terminal>:9050/docs.

    +

    TODO: adicionar screenshot da Swagger UI do TEF IP

    +
    +

    GET /openapi.bundle.yaml

    +

    Retorna o spec OpenAPI completo em formato YAML. O spec inclui a lista de servidores detectados + dinamicamente, incluindo o status de cada instância (Online/Offline).

    +

    Resposta — 200

    +
    +
    openapi: 3.0.0
     info:
       title: TEF IP API
       version: 1.0.0
    @@ -1384,20 +1430,23 @@ 

    GET /openapi.bundle.yaml

    description: Online - url: http://192.168.1.101:9050 description: Offline -
    -

    O arquivo pode ser importado em qualquer ferramenta compatível com OpenAPI (Postman, Insomnia, etc.).

    -

    Como importar no Postman

    -
      -
    1. Abra o Postman e clique em Import.
    2. -
    3. Selecione Link e cole: http://<ip-do-terminal>:9050/openapi.bundle.yaml
    4. -
    5. Clique em Continue e confirme a importação.
    6. -
    -

    Como importar no Insomnia

    -
      -
    1. Abra o Insomnia e clique em CreateImport from URL.
    2. -
    3. Cole: http://<ip-do-terminal>:9050/openapi.bundle.yaml
    4. -
    5. Confirme a importação.
    6. -
    +
    +
    +

    O arquivo pode ser importado em qualquer ferramenta compatível com OpenAPI (Postman, Insomnia, etc.).

    +

    Como importar no Postman

    +
      +
    1. Abra o Postman e clique em Import.
    2. +
    3. Selecione Link e cole: + http://<ip-do-terminal>:9050/openapi.bundle.yaml +
    4. +
    5. Clique em Continue e confirme a importação.
    6. +
    +

    Como importar no Insomnia

    +
      +
    1. Abra o Insomnia e clique em CreateImport from URL.
    2. +
    3. Cole: http://<ip-do-terminal>:9050/openapi.bundle.yaml
    4. +
    5. Confirme a importação.
    6. +
    @@ -1410,52 +1459,54 @@

    Como importar no Insomnia

    - - -
    - - - - + - - - - - - -
    -
    -
    - - - - - - - - - - - - - - +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/api/transaction/index.html b/site/api/transaction/index.html index 73ccbdb..10e230d 100644 --- a/site/api/transaction/index.html +++ b/site/api/transaction/index.html @@ -1,1501 +1,1546 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Transações - TEF IP Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + Pular para conteúdo + + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    -
    -
    -
    - - - - - - - - - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - -
    -
    -
    - - - - - - - -
    - -
    - - - - - -

    Transações

    -

    Endpoints para processar pagamentos, consultar histórico e realizar estornos.

    -
    -

    Autenticação

    -

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instalação).

    -
    -
    -

    POST /transaction

    -

    Inicia um pagamento no terminal. O TEF IP aguarda o app estar em primeiro plano por até 15 segundos antes de processar — se o app estiver minimizado, o endpoint retorna 503.

    -
    -

    App em segundo plano

    -

    Se o TEF IP estiver minimizado, aguarda até 15 s pelo retorno ao primeiro plano antes de processar — caso contrário retorna 503. Veja Comportamento → App em segundo plano.

    -
    -

    Corpo da requisição

    - +
    +
    + + + +
    + +
    + + + + + +

    Transações

    +

    Endpoints para processar pagamentos, consultar histórico e realizar estornos.

    +
    +

    Autenticação

    +

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / + senha definida na instalação).

    +
    +
    +

    POST /transaction

    +

    Inicia um pagamento no terminal. O TEF IP aguarda o app estar em primeiro plano por até 15 + segundos antes de processar — se o app estiver minimizado, o endpoint retorna 503. +

    +
    +

    App em segundo plano

    +

    Se o TEF IP estiver minimizado, aguarda até 15 s pelo retorno ao primeiro plano antes + de processar — caso contrário retorna 503. Veja Comportamento → App em segundo plano.

    +
    +

    Corpo da requisição

    +
    +
    {
       "tPag": "17",
       "amount": 50.00,
       "referenceId": "pedido-001",
    @@ -1503,119 +1548,125 @@ 

    POST /transaction

    "installmentType": "single", "details": {} } -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoObrigatórioDescrição
    tPagstringSimTipo de pagamento (ver tabela abaixo)
    amountnumberSimValor da transação
    referenceIdstringNãoIdentificador externo para conciliação. Sem este campo, a transação não pode ser estornada individualmente — aparece apenas na listagem geral. Use o número do pedido ou UUID da venda.
    installmentsintNãoNúmero de parcelas (padrão: 1)
    installmentTypestringNãoModalidade de parcelamento (padrão: "single")
    detailsobjectNãoMetadados adicionais da transação
    -
    -

    referenceId é necessário para estornos

    -

    Sem referenceId, a transação só aparece na listagem geral (GET /transaction) e não pode ser estornada individualmente. Defina-o sempre que a operação puder precisar de estorno futuro.

    -
    -

    Valores de tPag

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ValorDescrição
    "01"Dinheiro
    "03"Crédito
    "04"Débito
    "05"Cartão-presente
    "17"PIX
    "99"Desconhecido
    -

    Valores de installmentType

    - - - - - - - - - - - - - - - - - - - - - -
    ValorDescrição
    "single"Pagamento à vista (padrão)
    "seller"Parcelado pelo lojista (sem juros ao comprador)
    "buyer"Parcelado pelo comprador (juros ao comprador)
    -

    Resposta — 200

    -
    {
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoObrigatórioDescrição
    tPagstringSimTipo de pagamento (ver tabela abaixo)
    amountnumberSimValor da transação
    referenceIdstringNãoIdentificador externo para conciliação. Sem este campo, a transação não pode ser estornada + individualmente — aparece apenas na listagem geral. Use o número do pedido ou UUID da + venda.
    installmentsintNãoNúmero de parcelas (padrão: 1)
    installmentTypestringNãoModalidade de parcelamento (padrão: "single")
    detailsobjectNãoMetadados adicionais da transação
    +
    +

    referenceId é necessário para estornos

    +

    Sem referenceId, a transação só aparece na listagem geral (GET /transaction) + e não pode ser estornada individualmente. Defina-o sempre que a operação puder precisar de estorno + futuro.

    +
    +

    Valores de tPag

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ValorDescrição
    "01"Dinheiro
    "03"Crédito
    "04"Débito
    "05"Cartão-presente
    "17"PIX
    "99"Desconhecido
    +

    Valores de installmentType

    + + + + + + + + + + + + + + + + + + + + + +
    ValorDescrição
    "single"Pagamento à vista (padrão)
    "seller"Parcelado pelo lojista (sem juros ao comprador)
    "buyer"Parcelado pelo comprador (juros ao comprador)
    +

    Resposta — 200

    +
    +
    {
       "nsu": "123456",
       "cnpj": "05481336000137",
       "cAut": "123456",
    @@ -1624,71 +1675,84 @@ 

    POST /transaction

    "tPag": "17", "details": {} } -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoDescrição
    nsustringNúmero sequencial único gerado pelo adquirente
    cnpjstringCNPJ do adquirente/emissor retornado pelo terminal
    cAutstringCódigo de autorização — presente em crédito/débito; null em PIX
    txidstringIdentificador da transação — presente apenas em PIX; null nos demais tipos
    tBandstringBandeira do cartão retornada pelo adquirente
    tPagstringCódigo do tipo de pagamento (ver tabela de tPag)
    detailsobjectDados adicionais retornados pelo adquirente
    -

    Resposta — 503 (app em segundo plano)

    -
    {
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoDescrição
    nsustringNúmero sequencial único gerado pelo adquirente
    cnpjstringCNPJ do adquirente/emissor retornado pelo terminal
    cAutstringCódigo de autorização — presente em crédito/débito; null em PIX
    txidstringIdentificador da transação — presente apenas em PIX; null nos demais + tipos
    tBandstringBandeira do cartão retornada pelo adquirente
    tPagstringCódigo do tipo de pagamento (ver tabela de tPag)
    detailsobjectDados adicionais retornados pelo adquirente
    +

    Resposta — 503 (app em segundo plano)

    +
    +
    {
       "code": 503,
       "message": "Aplicativo em segundo plano. Abra o app para concluir o pagamento."
     }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X POST http://localhost:9050/transaction \
          -d '{"tPag":"17","amount":50.00,"referenceId":"pedido-001"}'
    -
    -
    -
    -
    // pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
    +
    +
    +
    +
    +
    +
    // pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
     TefIP.baseUrl = 'http://localhost:9050';
     TefIP.username = 'admin';
     TefIP.password = '1234';
    @@ -1702,10 +1766,12 @@ 

    Exemplos de integração

    print(result.nsu); // NSU do adquirente print(result.txid); // preenchido em PIX print(result.cAut); // preenchido em crédito/débito -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/transaction', {
       method: 'POST',
       headers: {
    @@ -1715,10 +1781,12 @@ 

    Exemplos de integração

    body: JSON.stringify({ tPag: '17', amount: 50.00, referenceId: 'pedido-001' }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/transaction');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -1732,10 +1800,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1745,16 +1815,18 @@ 

    Exemplos de integração

    req.body = { tPag: '17', amount: 50.00, referenceId: 'pedido-001' }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    GET /transaction

    -

    Lista todas as transações registradas no terminal.

    -

    Resposta — 200

    -

    Array de transações, cada uma com a mesma estrutura do retorno de POST /transaction.

    -
    [
    +
    +
    +
    +
    +
    +
    +

    GET /transaction

    +

    Lista todas as transações registradas no terminal.

    +

    Resposta — 200

    +

    Array de transações, cada uma com a mesma estrutura do retorno de POST /transaction.

    +
    +
    [
       {
         "nsu": "123456",
         "cnpj": "05481336000137",
    @@ -1765,44 +1837,60 @@ 

    GET /transaction

    "details": {} } ] -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          http://localhost:9050/transaction
    -
    -
    -
    -
    final transactions = await TefIP.instance.transaction.getAll();
    +
    +
    +
    +
    +
    +
    final transactions = await TefIP.instance.transaction.getAll();
     for (final t in transactions) {
       print(t.nsu);
     }
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/transaction', {
       headers: {
         'Authorization': 'Basic ' + btoa('admin:1234'),
       },
     });
     const data = await res.json();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/transaction');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
     $response = json_decode(curl_exec($ch), true);
     curl_close($ch);
    -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1811,32 +1899,34 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    GET /transaction/{referenceId}

    -

    Busca uma transação específica pelo identificador externo informado no momento do pagamento.

    -

    Parâmetros de rota

    - - - - - - - - - - - - - - - -
    ParâmetroTipoDescrição
    referenceIdstringIdentificador externo da transação
    -

    Resposta — 200

    -
    {
    +
    +
    +
    +
    +
    +
    +

    GET /transaction/{referenceId}

    +

    Busca uma transação específica pelo identificador externo informado no momento do pagamento.

    +

    Parâmetros de rota

    + + + + + + + + + + + + + + + +
    ParâmetroTipoDescrição
    referenceIdstringIdentificador externo da transação
    +

    Resposta — 200

    +
    +
    {
       "nsu": "123456",
       "cnpj": "05481336000137",
       "cAut": "123456",
    @@ -1845,32 +1935,46 @@ 

    GET /transaction/{referenceId}

    "tPag": "17", "details": {} } -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          http://localhost:9050/transaction/pedido-001
    -
    -
    -
    -
    final transaction = await TefIP.instance.transaction.get(referenceId: 'pedido-001');
    +
    +
    +
    +
    +
    +
    final transaction = await TefIP.instance.transaction.get(referenceId: 'pedido-001');
     print(transaction.nsu);
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/transaction/pedido-001', {
       headers: {
         'Authorization': 'Basic ' + btoa('admin:1234'),
       },
     });
     const data = await res.json();
    -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $referenceId = 'pedido-001';
     $ch = curl_init("http://localhost:9050/transaction/{$referenceId}");
    @@ -1878,10 +1982,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1891,34 +1997,37 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    POST /transaction/{referenceId}/reversal

    -

    Realiza o estorno de uma transação pelo seu referenceId. Assim como o pagamento, aguarda o app estar em primeiro plano por até 15 segundos.

    -

    Parâmetros de rota

    - - - - - - - - - - - - - - - -
    ParâmetroTipoDescrição
    referenceIdstringIdentificador externo da transação a estornar
    -

    Não há corpo na requisição.

    -

    Resposta — 200

    -

    Mesma estrutura de POST /transaction.

    -
    {
    +
    +
    +
    +
    +
    +
    +

    POST /transaction/{referenceId}/reversal

    +

    Realiza o estorno de uma transação pelo seu referenceId. Assim como o pagamento, aguarda o + app estar em primeiro plano por até 15 segundos.

    +

    Parâmetros de rota

    + + + + + + + + + + + + + + + +
    ParâmetroTipoDescrição
    referenceIdstringIdentificador externo da transação a estornar
    +

    Não há corpo na requisição.

    +

    Resposta — 200

    +

    Mesma estrutura de POST /transaction.

    +
    +
    {
       "nsu": "123456",
       "cnpj": "05481336000137",
       "cAut": "123456",
    @@ -1927,28 +2036,42 @@ 

    POST /transaction/{referenceId}/rev "tPag": "17", "details": {} } -

    -

    Resposta — 503 (app em segundo plano)

    -
    {
    +
    +
    +

    Resposta — 503 (app em segundo plano)

    +
    +
    {
       "code": 503,
       "message": "Aplicativo em segundo plano. Abra o app para concluir o estorno."
     }
    -
    -

    Exemplos de integração

    -
    -
    -
    -
    curl -u admin:1234 \
    +
    +
    +

    Exemplos de integração

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -X POST http://localhost:9050/transaction/pedido-001/reversal
    -
    -
    -
    -
    final result = await TefIP.instance.reversal.post(referenceId: 'pedido-001');
    +
    +
    +
    +
    +
    +
    final result = await TefIP.instance.reversal.post(referenceId: 'pedido-001');
     print(result.nsu);
    -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/transaction/pedido-001/reversal', {
       method: 'POST',
       headers: {
    @@ -1956,10 +2079,12 @@ 

    Exemplos de integração

    }, }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $referenceId = 'pedido-001';
     $ch = curl_init("http://localhost:9050/transaction/{$referenceId}/reversal");
    @@ -1968,10 +2093,12 @@ 

    Exemplos de integração

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1981,10 +2108,11 @@ 

    Exemplos de integração

    req.basic_auth('admin', '1234') res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    +
    +
    +
    +
    +
    @@ -1997,52 +2125,54 @@

    Exemplos de integração

    - - -
    - - - - + - - - - - - -
    -
    -
    - - - - - - - - - - - - - - +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/comportamento/index.html b/site/comportamento/index.html index a950560..0e44701 100644 --- a/site/comportamento/index.html +++ b/site/comportamento/index.html @@ -1,1733 +1,1818 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Comportamento - TEF IP Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + Pular para conteúdo + + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    -
    -
    -
    - - - - - - - - - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - -
    -
    -
    - - - - - - - -
    - -
    - - - - - -

    Comportamento do Servidor

    -

    Esta página descreve como o TEF IP se comporta em situações que afetam diretamente a sua integração. Leia antes de implementar os endpoints — as decisões aqui (especialmente sobre referenceId e o comportamento de servidor ocupado) determinam se sua integração vai funcionar corretamente em produção.

    -
    -

    Leitura obrigatória antes de integrar

    -

    Desenvolvedores que pulam esta página frequentemente descobrem em produção que não conseguem estornar transações (por falta de referenceId) ou não tratam corretamente o 503 de servidor ocupado.

    -
    -
    -

    Fluxo de uma transação

    -

    Ao enviar um pagamento, o TEF IP repassa o comando ao terminal, que interage diretamente com o portador do cartão ou exibe o QR Code do PIX. A resposta do servidor só chega quando o pagamento é aprovado, recusado ou cancelado — o que pode levar vários segundos dependendo da rede e do adquirente.

    -

    Durante esse tempo o servidor fica bloqueado: nenhuma outra operação pode ser enviada até a transação ser concluída.

    -

    Sequência:

    -
      -
    1. PDV envia POST /transaction
    2. -
    3. TEF IP repassa ao terminal do adquirente
    4. -
    5. Terminal processa (cliente insere cartão, digita senha, confirma PIX…)
    6. -
    7. TEF IP retorna a resposta ao PDV
    8. -
    9. PDV pode enviar a próxima operação
    10. -
    -
    -

    Tempo de resposta

    -

    Dimensione o timeout do seu cliente HTTP para pelo menos 60 segundos — transações com cartão físico dependem da interação do cliente no terminal.

    -
    -
    -

    Identificação de transações

    -

    Para consultar ou estornar uma transação depois, você precisa de um identificador que ligue o seu sistema ao TEF IP. Esse identificador — chamado de referenceId — é informado pelo PDV no momento do pagamento.

    -
      -
    • Com referenceId: você pode consultar a transação diretamente e solicitar estorno a qualquer momento.
    • -
    • Sem referenceId: a transação aparece apenas na listagem geral e não pode ser estornada individualmente.
    • -
    -

    Use um identificador já existente no seu sistema — número do pedido, UUID da venda — qualquer valor único serve. O TEF IP armazena esse vínculo e o devolve na resposta.

    -
    -

    Fluxo de uma venda

    -

    Uma venda é uma sessão aberta que agrega itens e formas de pagamento antes de ser consolidada. Apenas uma venda pode estar ativa por vez — tentar abrir uma segunda enquanto há uma em aberto retorna 409.

    -
    -

    Venda e transação são independentes

    -

    A venda registra o quê foi vendido e como foi pago — mas não processa o pagamento financeiro. O débito no cartão ou PIX é feito separadamente via POST /transaction.

    -
    -

    Veja o ciclo de vida completo e os endpoints de venda →

    -
    -

    Cancelamento de item vs. exclusão

    -

    Ao remover um item de uma venda em aberto, você tem duas opções com comportamentos distintos:

    - - - - - - - - - - - - - - - - - -
    AçãoResultado
    Excluir o itemItem removido permanentemente — não aparece no cupom/NF
    Cancelar o itemItem mantido no histórico como cancelado — consta no cupom/NF com status cancelado
    -

    Use o cancelamento quando o item precisar aparecer no documento fiscal mesmo sem ser cobrado. Use a exclusão quando o item foi adicionado por engano e não deve constar em nenhum documento.

    -
    -

    Coleta de dados no terminal

    -

    O TEF IP pode exibir perguntas no display do terminal (CPF, texto livre, listas, e-mail, CEP…) e coletar respostas sem que o PDV precise de tela própria. A conexão HTTP fica aberta até o usuário confirmar ou cancelar.

    -

    Veja os endpoints e tipos de campo disponíveis em Perguntas (Ask) →

    -
    -

    Servidor ocupado

    -

    O TEF IP processa uma operação por vez. Enquanto um pagamento, estorno ou impressão está em andamento, o servidor recusa novas operações.

    -

    Operações que bloqueiam o servidor:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    EndpointOperação
    POST /transactionPagamento em processamento
    POST /transaction/{referenceId}/reversalEstorno em processamento
    POST /print/imageImpressão de imagem em andamento
    POST /print/textImpressão de texto em andamento
    POST /print/xmlImpressão de XML em andamento
    -

    O que acontece ao enviar uma requisição durante esse período:

    - +
    +
    + + + +
    + +
    + + + + + +

    Comportamento do Servidor

    +

    Esta página descreve como o TEF IP se comporta em situações que afetam diretamente a sua integração. Leia + antes de implementar os endpoints — as decisões aqui (especialmente sobre referenceId e o + comportamento de servidor ocupado) determinam se sua integração vai funcionar corretamente em produção. +

    +
    +

    Leitura obrigatória antes de integrar

    +

    Desenvolvedores que pulam esta página frequentemente descobrem em produção que não conseguem estornar + transações (por falta de referenceId) ou não tratam corretamente o 503 de + servidor ocupado.

    +
    +
    +

    Fluxo de uma transação

    +

    Ao enviar um pagamento, o TEF IP repassa o comando ao terminal, que interage diretamente com o portador + do cartão ou exibe o QR Code do PIX. A resposta do servidor só chega quando o pagamento é + aprovado, recusado ou cancelado — o que pode levar vários segundos dependendo da rede e + do adquirente. +

    +

    Durante esse tempo o servidor fica bloqueado: nenhuma outra operação pode ser enviada até a transação ser + concluída.

    +

    Sequência:

    +
      +
    1. PDV envia POST /transaction
    2. +
    3. TEF IP repassa ao terminal do adquirente
    4. +
    5. Terminal processa (cliente insere cartão, digita senha, confirma PIX…)
    6. +
    7. TEF IP retorna a resposta ao PDV
    8. +
    9. PDV pode enviar a próxima operação
    10. +
    +
    +

    Tempo de resposta

    +

    Dimensione o timeout do seu cliente HTTP para pelo menos 60 segundos — transações com cartão físico + dependem da interação do cliente no terminal.

    +
    +
    +

    Identificação de transações

    +

    Para consultar ou estornar uma transação depois, você precisa de um identificador que + ligue o seu sistema ao TEF IP. Esse identificador — chamado de referenceId — é informado pelo + PDV no momento do pagamento.

    +
      +
    • Com referenceId: você pode consultar a transação diretamente e solicitar + estorno a qualquer momento.
    • +
    • Sem referenceId: a transação aparece apenas na listagem geral e não pode + ser estornada individualmente.
    • +
    +

    Use um identificador já existente no seu sistema — número do pedido, UUID da venda — qualquer valor único + serve. O TEF IP armazena esse vínculo e o devolve na resposta.

    +
    +

    Fluxo de uma venda

    +

    Uma venda é uma sessão aberta que agrega itens e formas de pagamento antes de ser + consolidada. Apenas uma venda pode estar ativa por vez — tentar abrir uma segunda enquanto há uma em + aberto retorna 409.

    +
    +

    Venda e transação são independentes

    +

    A venda registra o quê foi vendido e como foi pago — mas não processa + o pagamento financeiro. O débito no cartão ou PIX é feito separadamente via + POST /transaction. +

    +
    +

    Veja o ciclo de vida completo e os endpoints de venda →

    +
    +

    Cancelamento de item vs. exclusão

    +

    Ao remover um item de uma venda em aberto, você tem duas opções com comportamentos distintos:

    + + + + + + + + + + + + + + + + + +
    AçãoResultado
    Excluir o itemItem removido permanentemente — não aparece no cupom/NF
    Cancelar o itemItem mantido no histórico como cancelado — consta no cupom/NF com status cancelado
    +

    Use o cancelamento quando o item precisar aparecer no documento fiscal mesmo sem ser cobrado. Use a + exclusão quando o item foi adicionado por engano e não deve constar em nenhum documento.

    +
    +

    Coleta de dados no terminal

    +

    O TEF IP pode exibir perguntas no display do terminal (CPF, texto livre, listas, e-mail, CEP…) e coletar + respostas sem que o PDV precise de tela própria. A conexão HTTP fica aberta até o usuário confirmar ou + cancelar.

    +

    Veja os endpoints e tipos de campo disponíveis em Perguntas (Ask) →

    +
    +

    Servidor ocupado

    +

    O TEF IP processa uma operação por vez. Enquanto um pagamento, estorno ou impressão está + em andamento, o servidor recusa novas operações.

    +

    Operações que bloqueiam o servidor:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    EndpointOperação
    POST /transactionPagamento em processamento
    POST /transaction/{referenceId}/reversalEstorno em processamento
    POST /print/imageImpressão de imagem em andamento
    POST /print/textImpressão de texto em andamento
    POST /print/xmlImpressão de XML em andamento
    +

    O que acontece ao enviar uma requisição durante esse período:

    +
    +
    {
       "code": 503,
       "message": "Aplicativo ocupado realizando outra operação, tente mais tarde!"
     }
    -
    -

    Como verificar se o servidor está livre:

    -

    Use GET /info para consultar o estado atual. Se o servidor estiver ocupado, aguarde antes de enviar uma nova operação.

    -
    -

    Endpoints sempre disponíveis

    -

    GET /status, GET /info e POST /restart respondem normalmente mesmo durante uma operação — use-os para monitorar o estado do servidor.

    -
    -
    -

    App em segundo plano

    -

    Pagamentos e estornos exigem que o TEF IP esteja visível na tela do terminal. Se o operador minimizou o app, o servidor aguarda automaticamente até 15 segundos pelo retorno ao primeiro plano.

    -

    O que acontece:

    -
      -
    1. O PDV envia POST /transaction ou POST /transaction/{referenceId}/reversal.
    2. -
    3. O TEF IP detecta que está minimizado e aguarda até 15 s.
    4. -
    5. Se o app retornar ao primeiro plano dentro do prazo, a operação prossegue normalmente.
    6. -
    7. Se não retornar, o servidor rejeita a requisição:
    8. -
    -
    {
    +
    +
    +

    Como verificar se o servidor está livre:

    +

    Use GET /info para consultar o estado atual. Se o servidor estiver ocupado, aguarde antes de + enviar uma nova operação.

    +
    +

    Endpoints sempre disponíveis

    +

    GET /status, GET /info e POST /restart respondem normalmente + mesmo durante uma operação — use-os para monitorar o estado do servidor.

    +
    +
    +

    App em segundo plano

    +

    Pagamentos e estornos exigem que o TEF IP esteja visível na tela do terminal. Se o + operador minimizou o app, o servidor aguarda automaticamente até 15 segundos pelo retorno + ao primeiro plano.

    +

    O que acontece:

    +
      +
    1. O PDV envia POST /transaction ou POST /transaction/{referenceId}/reversal. +
    2. +
    3. O TEF IP detecta que está minimizado e aguarda até 15 s.
    4. +
    5. Se o app retornar ao primeiro plano dentro do prazo, a operação prossegue normalmente.
    6. +
    7. Se não retornar, o servidor rejeita a requisição:
    8. +
    +
    +
    {
       "code": 503,
       "message": "Aplicativo em segundo plano. Abra o app para concluir o pagamento."
     }
    -
    -
    -

    Notificação automática

    -

    Ao receber o comando, o TEF IP envia uma notificação ao operador pedindo para restaurar o aplicativo. Veja a seção Notificações ao operador abaixo.

    -
    -

    Como verificar se o app está em primeiro plano:

    -

    Use GET /info para consultar o estado atual do aplicativo.

    -
    -

    Notificações ao operador

    -

    Sempre que o TEF IP recebe um comando do PDV, ele exibe automaticamente uma notificação no terminal alertando o operador para restaurar o aplicativo.

    -

    Isso é especialmente útil quando o operador minimizou o TEF IP — a notificação serve como aviso para que o app volte ao primeiro plano antes do tempo limite de 15 segundos expirar.

    -

    Nenhuma configuração é necessária — o comportamento é automático.

    -

    Se o seu fluxo precisar disparar um alerta manual fora desse comportamento automático, use o endpoint Notificações → POST /notification.

    -
    -

    Endpoints sem autenticação

    -

    A maioria dos endpoints exige Basic Auth. As únicas exceções são:

    - - - - - - - - - - - - - - - - - -
    EndpointDescrição
    GET /docsSwagger UI
    GET /openapi.bundle.yamlEspecificação OpenAPI
    -

    Todos os demais endpoints exigem credenciais válidas. Requisições sem autenticação ou com credenciais inválidas recebem 401.

    -
    -

    CORS

    -

    O TEF IP aceita requisições de qualquer origem. Nenhuma configuração adicional é necessária para clientes web ou browser:

    -
      -
    • Origens permitidas: todas
    • -
    • Métodos permitidos: GET, POST, PUT, DELETE, OPTIONS
    • -
    • Headers permitidos: qualquer
    • -
    • Preflight (OPTIONS): respondido com 204 No Content
    • -
    -
    -

    Respostas de erro

    -

    Todos os erros retornam { "code": <status>, "message": "..." }. Veja a Visão Geral de Erros → para a referência completa de códigos HTTP e sugestões de tratamento.

    - - - - - - - - - - - - - -
    +
    - - - +
    +

    Notificação automática

    +

    Ao receber o comando, o TEF IP envia uma notificação ao operador pedindo para restaurar o aplicativo. + Veja a seção Notificações ao operador abaixo.

    +
    +

    Como verificar se o app está em primeiro plano:

    +

    Use GET /info para consultar o estado atual do aplicativo.

    +
    +

    Notificações ao operador

    +

    Sempre que o TEF IP recebe um comando do PDV, ele exibe automaticamente uma notificação no terminal + alertando o operador para restaurar o aplicativo.

    +

    Isso é especialmente útil quando o operador minimizou o TEF IP — a notificação serve como aviso para que + o app volte ao primeiro plano antes do tempo limite de 15 segundos expirar.

    +

    Nenhuma configuração é necessária — o comportamento é automático.

    +

    Se o seu fluxo precisar disparar um alerta manual fora desse comportamento automático, use o endpoint Notificações → POST /notification.

    +
    +

    Endpoints sem autenticação

    +

    A maioria dos endpoints exige Basic Auth. As únicas exceções são:

    + + + + + + + + + + + + + + + + + +
    EndpointDescrição
    GET /docsSwagger UI
    GET /openapi.bundle.yamlEspecificação OpenAPI
    +

    Todos os demais endpoints exigem credenciais válidas. Requisições sem autenticação ou com credenciais + inválidas recebem 401.

    +
    +

    CORS

    +

    O TEF IP aceita requisições de qualquer origem. Nenhuma configuração adicional é necessária para clientes + web ou browser:

    +
      +
    • Origens permitidas: todas
    • +
    • Métodos permitidos: GET, POST, PUT, + DELETE, OPTIONS +
    • +
    • Headers permitidos: qualquer
    • +
    • Preflight (OPTIONS): respondido com 204 No Content
    • +
    +
    +

    Respostas de erro

    +

    Todos os erros retornam { "code": <status>, "message": "..." }. Veja a Visão Geral de Erros → para a referência completa de códigos HTTP e sugestões + de tratamento.

    + + + + + + + + + + + + + + +
    + + + + + + + + + + - - -
    -
    -
    - - - - - - - - - - - - - - +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/emulator/index.html b/site/emulator/index.html index 6d9e9c9..c183b2f 100644 --- a/site/emulator/index.html +++ b/site/emulator/index.html @@ -1,1497 +1,1555 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - Testando com Emulador - TEF IP Docs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - Pular para conteúdo - - -
    -
    - -
    - - - - -
    - - -
    - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  • - - - - - - - - - -
  • -
    -
    - - - -
    -
    - -
    -
    - - - -
    - -
    - - - - - -

    Emulador

    -

    O TEF IP inclui um modo emulador que simula o hardware do adquirente localmente — sem precisar de nenhum terminal físico. É a forma mais rápida de desenvolver e testar toda a integração com o TEF IP.

    -
    -

    Não usar em produção

    -

    O build com emulador é destinado exclusivamente a desenvolvimento e testes. Para uso em produção, utilize o app distribuído pelo seu adquirente no terminal Android correspondente (Stone, Getnet ou Rede).

    -
    -

    Veja abaixo um pagamento sendo processado no emulador:

    -

    GIF do terminal processando pagamento manual

    -
    -

    Download

    -

    Escolha a plataforma para desenvolvimento e testes:

    - - - - - - - - - - - - - - - - - - - - -
    PlataformaArquivoObservação
    Windows 10+TEF IP-emulador-setup.exeInstalador com assistente; registra o TEF IP como serviço do Windows
    Android (APK)TEF IP-emulador.apkSideload manual; não disponível na Play Store
    -
    -

    Onde baixar

    -

    Os arquivos de download são disponibilizados pelo canal TEF IP. Entre em contato com o suporte para obter o link de download da versão mais recente.

    -
    -
    -

    Instalação no Windows

    -
      -
    1. Execute o instalador TEF IP-emulador-setup.exe.
    2. -
    3. Siga o assistente de instalação (próximo → próximo → instalar).
    4. -
    5. Ao final, o TEF IP é registrado como serviço do Windows e inicia automaticamente com o sistema.
    6. -
    7. Um ícone aparecerá na bandeja do sistema — clique nele para abrir o painel de controle.
    8. -
    -

    GIF de instalação no Windows

    -

    Instalação do APK Android

    -
      -
    1. No dispositivo Android, acesse Configurações → Segurança e habilite "Fontes desconhecidas" (ou "Instalar apps desconhecidos").
    2. -
    3. Transfira o arquivo TEF IP-emulador.apk para o dispositivo (via USB, e-mail ou link direto).
    4. -
    5. Toque no arquivo .apk para iniciar a instalação e confirme.
    6. -
    7. Abra o app TEF IP após a instalação.
    8. -
    -
    -

    Dispositivo de testes

    -

    Qualquer smartphone ou tablet Android com Android 8.0+ funciona para desenvolvimento. Não é necessário nenhum hardware de adquirente.

    -
    -
    -

    Próximos passos

    - -
    -

    Dica de validação rápida

    -

    Depois da instalação, valide o emulador com GET /status em http://localhost:9050/status usando Basic Auth. Se precisar investigar comportamento interno, consulte também Logs.

    -
    - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - + + + + + + + + + + +
  • + + + + + Guia de Integração + + +
  • + + + + + + + + + + + +
  • + + + + + API Reference + + +
  • + + + + + + + + + + + +
  • + + + + + SDKs + + +
  • + + + + + + + + + + + +
  • + + + + + Suporte e Operações + + +
  • + + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    + +
    +
    + + + +
    + +
    + + + + + +

    Emulador

    +

    O TEF IP inclui um modo emulador que simula o hardware do adquirente localmente — sem + precisar de nenhum terminal físico. É a forma mais rápida de desenvolver e testar toda a integração com o + TEF IP.

    +
    +

    Não usar em produção

    +

    O build com emulador é destinado exclusivamente a desenvolvimento e testes. Para uso + em produção, utilize o app distribuído pelo seu adquirente no terminal Android correspondente (Stone, + Getnet ou Rede).

    +
    +

    Veja abaixo um pagamento sendo processado no emulador:

    +

    GIF do terminal processando pagamento manual +

    +
    +

    Download

    +

    Escolha a plataforma para desenvolvimento e testes:

    + + + + + + + + + + + + + + + + + + + + +
    PlataformaArquivoObservação
    Windows 10+TEF IP-emulador-setup.exeInstalador com assistente; registra o TEF IP como serviço do Windows
    Android (APK)TEF IP-emulador.apkSideload manual; não disponível na Play Store
    +
    +

    Onde baixar

    +

    Os arquivos de download são disponibilizados pelo canal TEF IP. Entre em contato com o suporte para + obter o link de download da versão mais recente.

    +
    +
    +

    Instalação no Windows

    +
      +
    1. Execute o instalador TEF IP-emulador-setup.exe.
    2. +
    3. Siga o assistente de instalação (próximo → próximo → instalar).
    4. +
    5. Ao final, o TEF IP é registrado como serviço do Windows e inicia automaticamente com + o sistema.
    6. +
    7. Um ícone aparecerá na bandeja do sistema — clique nele para abrir o painel de controle.
    8. +
    +

    GIF de instalação no Windows

    +

    Instalação do APK Android

    +
      +
    1. No dispositivo Android, acesse Configurações → Segurança e habilite "Fontes + desconhecidas" (ou "Instalar apps desconhecidos").
    2. +
    3. Transfira o arquivo TEF IP-emulador.apk para o dispositivo (via USB, e-mail ou link + direto).
    4. +
    5. Toque no arquivo .apk para iniciar a instalação e confirme.
    6. +
    7. Abra o app TEF IP após a instalação.
    8. +
    +
    +

    Dispositivo de testes

    +

    Qualquer smartphone ou tablet Android com Android 8.0+ funciona para desenvolvimento. Não é necessário + nenhum hardware de adquirente.

    +
    +
    +

    Próximos passos

    + +
    +

    Dica de validação rápida

    +

    Depois da instalação, valide o emulador com GET /status em + http://localhost:9050/status usando Basic Auth. Se precisar investigar comportamento + interno, consulte também Logs. +

    +
    + + + + + + + + + + + + + +
    +
    + + + + + +
    + +
    + + + + +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/getting-started/index.html b/site/getting-started/index.html index f336381..2c11c51 100644 --- a/site/getting-started/index.html +++ b/site/getting-started/index.html @@ -1,1507 +1,1575 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Primeiros Passos - TEF IP Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + Pular para conteúdo + + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    -
    -
    -
    - - - - - - - - - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - -
    -
    -
    - - - - + + + +
    + +
    + + + + + +

    Primeiros Passos

    +

    Este guia leva você da instalação até a primeira resposta real do terminal de pagamento. Ao final, você + terá o servidor rodando e confirmará que ele responde às suas requisições — pronto para começar a integrar + os endpoints de pagamento.

    +

    Pré-requisitos

    +
      +
    • Hardware: terminal Android compatível (Stone, Getnet ou Rede) ou + computador com Windows 10 ou superior
    • +
    • Rede local: o PDV e o terminal devem estar na mesma rede (ou usar + localhost quando o TEF IP rodar na mesma máquina) +
    • +
    +

    Instalação

    +

    Terminais Android (Adquirentes)

    +

    A instalação em terminais físicos é feita diretamente pela loja ou canal de distribuição do seu + adquirente — o processo varia para cada um:

    +
      +
    • Stone: distribuído pela Stone via portal de parceiros.
    • +
    • Getnet: distribuído pela Getnet via canal de desenvolvedores.
    • +
    • Rede: distribuído pela Rede via canal de parceiros.
    • +
    +

    Caso encontre alguma dificuldade, entre em contato com o nosso SUPORTE. +

    +

    Windows (Emulador — desenvolvimento/testes)

    +
      +
    1. Baixe o instalador .exe na página do Emulador.
    2. +
    3. Execute o instalador e siga o assistente de instalação.
    4. +
    5. Ao final, o TEF IP será registrado como serviço do Windows e iniciará automaticamente.
    6. +
    +
    +

    Build com emulador

    +

    O instalador Windows disponível nas releases inclui o emulador de hardware — ideal para desenvolvimento + e testes sem terminal físico. Para uso em produção, utilize o app distribuído pelo seu adquirente no + terminal Android correspondente.

    +
    +

    Emulador (APK Android) (Emulador — + desenvolvimento/testes)

    +

    O APK Android disponível na página do Emulador é o build com emulador + de hardware — destinado a desenvolvimento e testes sem terminal físico.

    +
    +

    Não usar em produção

    +

    Este APK não deve ser instalado em terminais físicos de produção (Stone, Getnet, + Rede). Para terminais físicos, obtenha o app pelo canal do seu adquirente conforme descrito acima.

    +
    +

    Iniciando o servidor

    +

    Se for o primeiro acesso, a inicialização automática já estará ativa.

    +

    Para verificar os servidores ativos:

    +
      +
    1. Abra o aplicativo TEF IP no terminal.
    2. +
    3. Acesse a seção Servidores na tela inicial.
    4. +
    5. Se não aparecer na tela inicial, abra o menu → Configurações → Servidores.
    6. +
    +

    Nessa tela é possível visualizar os IPs detectados e executar ações como reiniciar ou parar os serviços. +

    +

    GIF do TEF IP entrando nos servidores ativos +

    +

    Verificando a conexão

    +
    +

    Autenticação

    +

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / + senha definida na instalação). Os únicos endpoints sem autenticação são /docs e + /openapi.bundle.yaml. +

    +
    +

    Use o endpoint GET /status para confirmar que o servidor está respondendo:

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
    +     http://localhost:9050/status
    +
    -
    - - - -
    - -
    - - - - - -

    Primeiros Passos

    -

    Este guia leva você da instalação até a primeira resposta real do terminal de pagamento. Ao final, você terá o servidor rodando e confirmará que ele responde às suas requisições — pronto para começar a integrar os endpoints de pagamento.

    -

    Pré-requisitos

    -
      -
    • Hardware: terminal Android compatível (Stone, Getnet ou Rede) ou computador com Windows 10 ou superior
    • -
    • Rede local: o PDV e o terminal devem estar na mesma rede (ou usar localhost quando o TEF IP rodar na mesma máquina)
    • -
    -

    Instalação

    -

    Terminais Android (Adquirentes)

    -

    A instalação em terminais físicos é feita diretamente pela loja ou canal de distribuição do seu adquirente — o processo varia para cada um:

    -
      -
    • Stone: distribuído pela Stone via portal de parceiros.
    • -
    • Getnet: distribuído pela Getnet via canal de desenvolvedores.
    • -
    • Rede: distribuído pela Rede via canal de parceiros.
    • -
    -

    Caso encontre alguma dificuldade, entre em contato com o nosso SUPORTE.

    -

    Windows (Emulador — desenvolvimento/testes)

    -
      -
    1. Baixe o instalador .exe na página do Emulador.
    2. -
    3. Execute o instalador e siga o assistente de instalação.
    4. -
    5. Ao final, o TEF IP será registrado como serviço do Windows e iniciará automaticamente.
    6. -
    -
    -

    Build com emulador

    -

    O instalador Windows disponível nas releases inclui o emulador de hardware — ideal para desenvolvimento e testes sem terminal físico. Para uso em produção, utilize o app distribuído pelo seu adquirente no terminal Android correspondente.

    -
    -

    Emulador (APK Android) (Emulador — desenvolvimento/testes)

    -

    O APK Android disponível na página do Emulador é o build com emulador de hardware — destinado a desenvolvimento e testes sem terminal físico.

    -
    -

    Não usar em produção

    -

    Este APK não deve ser instalado em terminais físicos de produção (Stone, Getnet, Rede). Para terminais físicos, obtenha o app pelo canal do seu adquirente conforme descrito acima.

    -
    -

    Iniciando o servidor

    -

    Se for o primeiro acesso, a inicialização automática já estará ativa.

    -

    Para verificar os servidores ativos:

    -
      -
    1. Abra o aplicativo TEF IP no terminal.
    2. -
    3. Acesse a seção Servidores na tela inicial.
    4. -
    5. Se não aparecer na tela inicial, abra o menu → Configurações → Servidores.
    6. -
    -

    Nessa tela é possível visualizar os IPs detectados e executar ações como reiniciar ou parar os serviços.

    -

    GIF do TEF IP entrando nos servidores ativos

    -

    Verificando a conexão

    -
    -

    Autenticação

    -

    Todas as requisições exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instalação). Os únicos endpoints sem autenticação são /docs e /openapi.bundle.yaml.

    -
    -

    Use o endpoint GET /status para confirmar que o servidor está respondendo:

    -
    -
    -
    -
    curl -u admin:1234 \
    -     http://localhost:9050/status
    -
    -
    -
    -
    import 'package:dart_tefip/dart_tefip.dart';
    +                
    +
    +
    import 'package:dart_tefip/dart_tefip.dart';
     
     TefIP.baseUrl = 'http://localhost:9050';
     TefIP.username = 'admin';
    @@ -1509,10 +1577,12 @@ 

    Verificando a conexão

    final status = await TefIP.instance.status.get(); print(status); -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/status', {
       headers: {
         'Authorization': 'Basic ' + btoa('admin:1234'),
    @@ -1520,10 +1590,12 @@ 

    Verificando a conexão

    }); const data = await res.json(); console.log(data); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/status');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -1531,10 +1603,12 @@ 

    Verificando a conexão

    $response = json_decode(curl_exec($ch), true); curl_close($ch); print_r($response); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1544,25 +1618,31 @@ 

    Verificando a conexão

    res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) puts data -
    -
    -
    -
    -

    Resposta esperada:

    -
    {
    +
    +
    +
    +
    +
    +

    Resposta esperada:

    +
    +
    {
       "status": "ok",
       "uptimeSeconds": 144,
       "startedAt": "2026-01-28T16:20:53.223883"
     }
    -
    -

    Próximos passos

    -

    Com o servidor respondendo, o caminho natural é:

    -
      -
    1. Comportamento — entenda como o servidor lida com operações simultâneas, app em segundo plano e autenticação antes de integrar os endpoints.
    2. -
    3. Transações — processe pagamentos e estornos.
    4. -
    5. Vendas — monte carrinho com itens e múltiplas formas de pagamento.
    6. -
    7. Swagger UI — explore e teste todos os endpoints diretamente no terminal.
    8. -
    +
    +
    +

    Próximos passos

    +

    Com o servidor respondendo, o caminho natural é:

    +
      +
    1. Comportamento — entenda como o servidor lida com + operações simultâneas, app em segundo plano e autenticação antes de integrar os endpoints.
    2. +
    3. Transações — processe pagamentos e estornos.
    4. +
    5. Vendas — monte carrinho com itens e múltiplas formas de + pagamento.
    6. +
    7. Swagger UI — explore e teste todos os endpoints + diretamente no terminal.
    8. +
    @@ -1575,52 +1655,54 @@

    Próximos passos

    - -
    -
    - - - - +
    - -
    - -
    - - + + + + +
    - - - -
    -
    -
    - - - - - - - - - - - - - - +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/index.html b/site/index.html index 1942656..e6e41ac 100644 --- a/site/index.html +++ b/site/index.html @@ -1,1392 +1,1432 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + TEF IP Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + Pular para conteúdo + + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    -
    -
    -
    - - - - - - - - - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - -
    -
    -
    - - - - - - - -
    - -
    +
    +
    + + + +
    + +
    + + + + + +

    TEF IP

    +

    Aceite pagamentos com qualquer adquirente usando uma única API HTTP local. Instale no terminal e comece a + processar.

    +
    +

    Como funciona

    +
    flowchart LR
         PDV["Seu sistema<br>(qualquer linguagem)"]
         tefip["TEF IP<br>IP Local"]
         HW["Adquirente"]
    @@ -1395,41 +1435,60 @@ 

    Como funciona

    tefip -- "SDK do adquirente" --> HW HW -- "aprovação / erro" --> tefip tefip -- "JSON" --> PDV
    -

    Seu sistema faz chamadas HTTP para o TEF IP. O TEF IP se comunica com o hardware do adquirente e retorna o resultado em JSON, sem nenhuma SDK proprietária no seu lado.

    -
    -

    Sem maquininha? Use o emulador!

    -

    O TEF IP inclui um modo emulador que simula o hardware do adquirente localmente. -Você pode desenvolver e testar toda a integração sem nenhum terminal físico. -Clique aqui para saber como usar o emulador

    -
    -

    Veja abaixo um pagamento sendo processado no emulador:

    -

    GIF do terminal processando pagamento manual

    -
    -

    O que você pode fazer

    -
      -
    • Pagamentos — Crédito, débito, PIX, dinheiro, voucher, cartão-presente; parcelamento pelo lojista ou pela emissora.
    • -
    • Vendas — Monte um carrinho com itens e adicione múltiplas formas de pagamento; finalize com uma chamada.
    • -
    • Estornos — Consulte e reverta transações por referenceId.
    • -
    • Display — Exiba textos, imagens, carrosséis ou QR codes na tela do terminal em tempo real.
    • -
    • Perguntas — Colete dados do cliente direto no terminal: CPF/CNPJ, texto livre, lista de opções, e-mail, CEP e mais.
    • -
    • Impressão — Imprima imagens, comprovantes personalizados, layouts ACBr ou cupons fiscais (XML/DANFE).
    • -
    • Logs e alertas — Consulte logs, acompanhe eventos em tempo real e dispare notificações locais ao operador.
    • -
    • Status — Monitore saúde, tempo de atividade e reinicie o app remotamente.
    • -
    -
    -

    Integração rápida

    -

    Qualquer cliente HTTP funciona. Veja um exemplo completo, um PIX de R$ 50,00, nas linguagens mais comuns:

    -
    -
    -
    -
    curl -u admin:1234 \
    +            

    Seu sistema faz chamadas HTTP para o TEF IP. O TEF IP se comunica com o hardware do adquirente e retorna + o resultado em JSON, sem nenhuma SDK proprietária no seu lado.

    +
    +

    Sem maquininha? Use o emulador!

    +

    O TEF IP inclui um modo emulador que simula o hardware do adquirente localmente. + Você pode desenvolver e testar toda a integração sem nenhum terminal físico. + Clique aqui para saber como usar o emulador +

    +
    +

    Veja abaixo um pagamento sendo processado no emulador:

    +

    GIF do terminal processando pagamento manual

    +
    +

    O que você pode fazer

    +
      +
    • Pagamentos — Crédito, débito, PIX, dinheiro, voucher, cartão-presente; parcelamento + pelo lojista ou pela emissora.
    • +
    • Vendas — Monte um carrinho com itens e adicione múltiplas formas de pagamento; + finalize com uma chamada.
    • +
    • Estornos — Consulte e reverta transações por referenceId.
    • +
    • Display — Exiba textos, imagens, carrosséis ou QR codes na tela do terminal em tempo + real.
    • +
    • Perguntas — Colete dados do cliente direto no terminal: CPF/CNPJ, texto livre, lista + de opções, e-mail, CEP e mais.
    • +
    • Impressão — Imprima imagens, comprovantes personalizados, layouts ACBr ou cupons + fiscais (XML/DANFE).
    • +
    • Logs e alertas — Consulte logs, acompanhe eventos em tempo real e dispare + notificações locais ao operador.
    • +
    • Status — Monitore saúde, tempo de atividade e reinicie o app remotamente.
    • +
    +
    +

    Integração rápida

    +

    Qualquer cliente HTTP funciona. Veja um exemplo completo, um PIX de R$ 50,00, nas linguagens mais comuns: +

    +
    +
    +
    +
    +
    +
    curl -u admin:1234 \
          -H "Content-Type: application/json" \
          -X POST http://localhost:9050/transaction \
          -d '{"tPag":"17","amount":50.00,"referenceId":"pedido-001"}'
    -
    -
    -
    -
    import 'package:dart_tefip/dart_tefip.dart';
    +
    +
    +
    +
    +
    +
    import 'package:dart_tefip/dart_tefip.dart';
     
     TefIP.baseUrl = 'http://localhost:9050';
     TefIP.username = 'admin';
    @@ -1442,10 +1501,12 @@ 

    Integração rápida

    referenceId: 'pedido-001', ), ); -
    -
    -
    -
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
    +
    +
    +
    +
    +
    +
    // TODO: pacote JavaScript ainda não criado — usando fetch diretamente
     const res = await fetch('http://localhost:9050/transaction', {
       method: 'POST',
       headers: {
    @@ -1455,10 +1516,12 @@ 

    Integração rápida

    body: JSON.stringify({ tPag: '17', amount: 50.00, referenceId: 'pedido-001' }), }); const data = await res.json(); -
    -
    -
    -
    <?php
    +
    +
    +
    +
    +
    +
    <?php
     // TODO: pacote PHP ainda não criado — usando curl diretamente
     $ch = curl_init('http://localhost:9050/transaction');
     curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    @@ -1472,10 +1535,12 @@ 

    Integração rápida

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); -
    -
    -
    -
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
    +
    +
    +
    +
    +
    +
    # TODO: pacote Ruby ainda não criado — usando Net::HTTP diretamente
     require 'net/http'
     require 'json'
     
    @@ -1485,135 +1550,138 @@ 

    Integração rápida

    req.body = { 'tPag' => '17', amount: 50.00, referenceId: 'pedido-001' }.to_json res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) } data = JSON.parse(res.body) -
    -
    -
    -
    -
    -

    Adquirentes suportados

    -

    Cada build do TEF IP é compilado para um adquirente específico.

    - - -
    -

    SDKs disponíveis

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    LinguagemPacoteStatus
    Dart / Flutterdart_tefipDisponível
    JavaScriptSem pacote oficial no momento
    PHPSem pacote oficial no momento
    RubySem pacote oficial no momento
    -

    Qualquer cliente HTTP funciona diretamente; os SDKs são conveniência, não requisito.

    -
    -

    Próximos Passos

    -

    Novo por aqui? Comece pelo guia:

    -

    Primeiros Passos →

    -

    Instale o TEF IP, verifique a conexão e faça sua primeira requisição em menos de 10 minutos.

    - - - - - - - - - - - - - -
    + +
    + + - - - +
    +

    Adquirentes suportados

    +

    Cada build do TEF IP é compilado para um adquirente específico.

    + + +
    +

    SDKs disponíveis

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    LinguagemPacoteStatus
    Dart / Flutterdart_tefipDisponível
    JavaScriptSem pacote oficial no momento
    PHPSem pacote oficial no momento
    RubySem pacote oficial no momento
    +

    Qualquer cliente HTTP funciona diretamente; os SDKs são conveniência, não requisito.

    +
    +

    Próximos Passos

    +

    Novo por aqui? Comece pelo guia:

    +

    Primeiros Passos →

    +

    Instale o TEF IP, verifique a conexão e faça sua primeira requisição em menos de 10 minutos.

    + + + + + + + + - + + + + + - - - -
    - - + + + + + -
    - - -
    -
    -
    - - - - - - - - - - - - - - +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/sdk-dart/index.html b/site/sdk-dart/index.html index 6a53692..5c39266 100644 --- a/site/sdk-dart/index.html +++ b/site/sdk-dart/index.html @@ -1,1737 +1,1788 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Dart (Oficial) - TEF IP Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + Pular para conteúdo + + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    -
    -
    -
    - - - - - - - - - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - -
    -
    -
    - - - - - - - -
    - -
    - - - - - -

    SDK Dart

    -

    O dart_tefip é o SDK oficial para Dart e Flutter. Ele encapsula as chamadas HTTP do TEF IP com modelos tipados, serialização de payloads e exceções específicas para a API.

    -
    -

    Instalação

    -

    Adicione ao seu pubspec.yaml:

    - +
    +
    + + + +
    + +
    + + + + + +

    SDK Dart

    +

    O dart_tefip é o SDK oficial para Dart e + Flutter. Ele encapsula as chamadas HTTP do TEF IP com modelos tipados, serialização de payloads e exceções + específicas para a API.

    +
    +

    Instalação

    +

    Adicione ao seu pubspec.yaml:

    +
    +
    dependencies:
       dart_tefip: ^<versão>
    -
    -

    Depois execute:

    -
    dart pub get
    +
    +
    +

    Depois execute:

    +
    +
    dart pub get
     # ou
     flutter pub get
    -
    -
    -

    Configuração

    -

    O SDK usa o padrão singleton com setters estáticos:

    -
    import 'package:dart_tefip/dart_tefip.dart';
    +
    +
    +
    +

    Configuração

    +

    O SDK usa o padrão singleton com setters estáticos:

    +
    +
    import 'package:dart_tefip/dart_tefip.dart';
     
     TefIP.baseUrl = 'http://192.168.1.10:9050';
     TefIP.username = 'admin';
     TefIP.password = 'minha-senha';
    -
    -

    Para desenvolvimento local com o emulador:

    -
    TefIP.baseUrl = 'http://localhost:9050';
    -
    -
    -

    TefIPClient não existe

    -

    Não existe nenhuma classe TefIPClient no SDK. Use sempre TefIP.instance.

    -
    -
    -

    Chamando endpoints

    -

    Todos os endpoints ficam disponíveis via TefIP.instance.<grupo>.<método>(...):

    -
    final result = await TefIP.instance.transaction.post(
    +
    +
    +

    Para desenvolvimento local com o emulador:

    +
    +
    TefIP.baseUrl = 'http://localhost:9050';
    +
    +
    +
    +

    TefIPClient não existe

    +

    Não existe nenhuma classe TefIPClient no SDK. Use sempre TefIP.instance.

    +
    +
    +

    Chamando endpoints

    +

    Todos os endpoints ficam disponíveis via TefIP.instance.<grupo>.<método>(...): +

    +
    +
    final result = await TefIP.instance.transaction.post(
       transactionRequest: TransactionRequestModel(
         type: TefIPTransactionType.pix,
         amount: 50.00,
    @@ -1742,127 +1793,142 @@ 

    Chamando endpoints

    print(result.nsu); print(result.txid); // PIX print(result.cAut); // crédito/débito -
    -
    -

    Catálogo de métodos

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    GrupoMétodos disponíveis
    transactiongetAll(), get(referenceId:), post(transactionRequest:)
    reversalpost(referenceId:)
    statusget()
    infoget()
    restartpost()
    saleget(), post(request:), patch(request:), clear()
    saleItempost(item:), patch(itemId:, item:), delete(itemId:), cancel(itemId:), clear()
    salePaymentpost(payment:), patch(paymentId:, payment:), delete(paymentId:), clear()
    saleDiscountpost(discount:), patch(discountId:, discount:), delete(discountId:), clear()
    saleAdditionpost(addition:), patch(additionId:, addition:), delete(additionId:), clear()
    saleFinalizepost(), post(params:)
    saleCancelpost(), post(params:)
    askpost(questionRequest:)
    askFormpost(form:)
    askCancelpost()
    displayImagepost(imageData:)
    displayTextpost(displayTextRequest:)
    displayCarouselpost(displayCarouselRequest:)
    displayClearpost()
    displayPoppost()
    printImagepost(imageData:)
    printTextpost(text:)
    printXmlpost(xml:)
    loggetAll(level:, source:, dateFrom:, dateTo:, limit:, search:, includeDetails:), stream(), downloadZip(level:, source:, dateFrom:, dateTo:, limit:)
    notificationpost(request:)
    -
    -

    Sem accessor para ACBr

    -

    O SDK Dart atual não expõe um método dedicado para POST /print/acbr. Para esse endpoint, use HTTP direto.

    -
    -
    -

    Exemplos rápidos

    -

    Venda

    -
    await TefIP.instance.sale.post(
    +
    +
    +
    +

    Catálogo de métodos

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    GrupoMétodos disponíveis
    transactiongetAll(), get(referenceId:), post(transactionRequest:)
    reversalpost(referenceId:)
    statusget()
    infoget()
    restartpost()
    saleget(), post(request:), patch(request:), + clear() +
    saleItempost(item:), patch(itemId:, item:), delete(itemId:), + cancel(itemId:), clear() +
    salePaymentpost(payment:), patch(paymentId:, payment:), + delete(paymentId:), clear() +
    saleDiscountpost(discount:), patch(discountId:, discount:), + delete(discountId:), clear() +
    saleAdditionpost(addition:), patch(additionId:, addition:), + delete(additionId:), clear() +
    saleFinalizepost(), post(params:)
    saleCancelpost(), post(params:)
    askpost(questionRequest:)
    askFormpost(form:)
    askCancelpost()
    displayImagepost(imageData:)
    displayTextpost(displayTextRequest:)
    displayCarouselpost(displayCarouselRequest:)
    displayClearpost()
    displayPoppost()
    printImagepost(imageData:)
    printTextpost(text:)
    printXmlpost(xml:)
    loggetAll(level:, source:, dateFrom:, dateTo:, limit:, search:, includeDetails:), + stream(), downloadZip(level:, source:, dateFrom:, dateTo:, limit:) +
    notificationpost(request:)
    +
    +

    Sem accessor para ACBr

    +

    O SDK Dart atual não expõe um método dedicado para POST /print/acbr. Para esse endpoint, + use HTTP direto.

    +
    +
    +

    Exemplos rápidos

    +

    Venda

    +
    +
    await TefIP.instance.sale.post(
       request: SaleStartRequestModel(
         customerName: 'João Silva',
         total: 99.90,
    @@ -1877,9 +1943,11 @@ 

    Venda

    unitPrice: 10.00, ), ); -
    -

    Ask

    -
    final answer = await TefIP.instance.ask.post(
    +
    +
    +

    Ask

    +
    +
    final answer = await TefIP.instance.ask.post(
       questionRequest: AskSingleQuestionRequestModel(
         question: AskQuestionModel(type: TefIPQuestionType.cpfOrcnpj),
         parameters: AskParametersModel(),
    @@ -1887,9 +1955,11 @@ 

    Ask

    ); print(answer.value); -
    -

    Display

    -
    await TefIP.instance.displayText.post(
    +
    +
    +

    Display

    +
    +
    await TefIP.instance.displayText.post(
       displayTextRequest: DisplayTextRequestModel(
         content: [
           {'text': 'Aguardando operador'},
    @@ -1898,9 +1968,11 @@ 

    Display

    showCloseButton: false, ), ); -
    -

    Logs

    -
    final logs = await TefIP.instance.log.getAll(
    +
    +
    +

    Logs

    +
    +
    final logs = await TefIP.instance.log.getAll(
       level: TefIPLogLevel.error,
       limit: 50,
     );
    @@ -1908,26 +1980,33 @@ 

    Logs

    TefIP.instance.log.stream().listen((log) { print('[${log.level.name}] ${log.message}'); }); -
    -

    Notificações

    -
    await TefIP.instance.notification.post(
    +
    +
    +

    Notificações

    +
    +
    await TefIP.instance.notification.post(
       request: NotificationRequestModel(
         title: 'Novo pagamento',
         message: 'Restaure o aplicativo para processar',
       ),
     );
    -
    -
    -

    Timeout

    -

    Por padrão, o SDK não define timeout global. Isso é útil para fluxos de pagamento em que o terminal pode aguardar interação do operador ou do cliente por tempo indeterminado.

    -

    Para definir um timeout global:

    -
    TefIP.requestsTimeOut = const Duration(minutes: 2);
    -
    -

    Também é possível passar timeout: em chamadas que suportam override por requisição.

    -
    -

    Tratamento de exceções

    -

    Todo método do SDK pode lançar dois tipos de exceção:

    -
    try {
    +
    +
    +
    +

    Timeout

    +

    Por padrão, o SDK não define timeout global. Isso é útil para fluxos de pagamento em que o terminal pode + aguardar interação do operador ou do cliente por tempo indeterminado.

    +

    Para definir um timeout global:

    +
    +
    TefIP.requestsTimeOut = const Duration(minutes: 2);
    +
    +
    +

    Também é possível passar timeout: em chamadas que suportam override por requisição.

    +
    +

    Tratamento de exceções

    +

    Todo método do SDK pode lançar dois tipos de exceção:

    +
    +
    try {
       final result = await TefIP.instance.transaction.post(
         transactionRequest: TransactionRequestModel(
           type: TefIPTransactionType.pix,
    @@ -1942,320 +2021,323 @@ 

    Tratamento de exceções

    } on TefIPUnexpectedException catch (e) { print(e.exception); } -
    - - - - - - - - - - - - - - - - - - - - -
    ExceçãoQuando ocorreCampos
    TefIPRequestExceptionAPI retornou 4xx/5xx ou falha de conexão tratadastatusCode, message, rawBody?
    TefIPUnexpectedExceptionErro inesperado fora do fluxo HTTP padrãoexception
    -
    -

    Referência de enums

    -

    TefIPTransactionType

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ValortPagDescrição
    TefIPTransactionType.money"01"Dinheiro
    TefIPTransactionType.credit"03"Crédito
    TefIPTransactionType.debit"04"Débito
    TefIPTransactionType.pix"17"PIX
    TefIPTransactionType.unknown"99"Desconhecido
    -

    TefIPInstallmentType

    - - - - - - - - - - - - - - - - - - - - - -
    ValorDescrição
    TefIPInstallmentType.singleÀ vista
    TefIPInstallmentType.sellerParcelado pelo lojista
    TefIPInstallmentType.buyerParcelado pelo comprador
    -

    TefIPTransactionStatus

    - - - - - - - - - - - - - - - - - - - - - - - - - -
    ValorDescrição
    TefIPTransactionStatus.pendingPendente
    TefIPTransactionStatus.paidPago
    TefIPTransactionStatus.cancelledCancelado
    TefIPTransactionStatus.unknownDesconhecido
    -

    TefIPSalePaymentType

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ValorDescrição
    TefIPSalePaymentType.moneyDinheiro
    TefIPSalePaymentType.creditCrédito
    TefIPSalePaymentType.debitDébito
    TefIPSalePaymentType.giftCartão-presente
    TefIPSalePaymentType.pixPIX
    TefIPSalePaymentType.veroWalletCarteira digital Vero
    TefIPSalePaymentType.voucherVoucher
    TefIPSalePaymentType.admOperação administrativa
    TefIPSalePaymentType.cancelCancelamento de pagamento
    TefIPSalePaymentType.cancelDigitalWalletCancelamento de carteira digital
    TefIPSalePaymentType.unknownDesconhecido
    -

    TefIPQuestionType

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ValorDescrição
    TefIPQuestionType.listLista de opções
    TefIPQuestionType.buttonBotões de opção
    TefIPQuestionType.textTexto livre
    TefIPQuestionType.phoneTelefone
    TefIPQuestionType.numberSomente números
    TefIPQuestionType.cpfCPF
    TefIPQuestionType.cnpjCNPJ
    TefIPQuestionType.cpfOrcnpjCPF ou CNPJ
    TefIPQuestionType.emailE-mail
    TefIPQuestionType.cepCEP
    TefIPQuestionType.dateData
    TefIPQuestionType.timeHora
    TefIPQuestionType.moneyValor monetário
    TefIPQuestionType.regexRegex personalizada
    -

    TefIPCarouselTransition

    - - - - - - - - - - - - - - - - - - - - - -
    ValorDescrição
    TefIPCarouselTransition.fadeDissolve entre imagens
    TefIPCarouselTransition.slideDesliza entre imagens
    TefIPCarouselTransition.noneTroca instantânea
    - - - - - - - - - - - - - -
    +
    - - - + + + + + + + + + + + + + + + + + + + + +
    ExceçãoQuando ocorreCampos
    TefIPRequestExceptionAPI retornou 4xx/5xx ou falha de conexão tratadastatusCode, message, rawBody?
    TefIPUnexpectedExceptionErro inesperado fora do fluxo HTTP padrãoexception
    +
    +

    Referência de enums

    +

    TefIPTransactionType

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ValortPagDescrição
    TefIPTransactionType.money"01"Dinheiro
    TefIPTransactionType.credit"03"Crédito
    TefIPTransactionType.debit"04"Débito
    TefIPTransactionType.pix"17"PIX
    TefIPTransactionType.unknown"99"Desconhecido
    +

    TefIPInstallmentType

    + + + + + + + + + + + + + + + + + + + + + +
    ValorDescrição
    TefIPInstallmentType.singleÀ vista
    TefIPInstallmentType.sellerParcelado pelo lojista
    TefIPInstallmentType.buyerParcelado pelo comprador
    +

    TefIPTransactionStatus

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    ValorDescrição
    TefIPTransactionStatus.pendingPendente
    TefIPTransactionStatus.paidPago
    TefIPTransactionStatus.cancelledCancelado
    TefIPTransactionStatus.unknownDesconhecido
    +

    TefIPSalePaymentType

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ValorDescrição
    TefIPSalePaymentType.moneyDinheiro
    TefIPSalePaymentType.creditCrédito
    TefIPSalePaymentType.debitDébito
    TefIPSalePaymentType.giftCartão-presente
    TefIPSalePaymentType.pixPIX
    TefIPSalePaymentType.veroWalletCarteira digital Vero
    TefIPSalePaymentType.voucherVoucher
    TefIPSalePaymentType.admOperação administrativa
    TefIPSalePaymentType.cancelCancelamento de pagamento
    TefIPSalePaymentType.cancelDigitalWalletCancelamento de carteira digital
    TefIPSalePaymentType.unknownDesconhecido
    +

    TefIPQuestionType

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ValorDescrição
    TefIPQuestionType.listLista de opções
    TefIPQuestionType.buttonBotões de opção
    TefIPQuestionType.textTexto livre
    TefIPQuestionType.phoneTelefone
    TefIPQuestionType.numberSomente números
    TefIPQuestionType.cpfCPF
    TefIPQuestionType.cnpjCNPJ
    TefIPQuestionType.cpfOrcnpjCPF ou CNPJ
    TefIPQuestionType.emailE-mail
    TefIPQuestionType.cepCEP
    TefIPQuestionType.dateData
    TefIPQuestionType.timeHora
    TefIPQuestionType.moneyValor monetário
    TefIPQuestionType.regexRegex personalizada
    +

    TefIPCarouselTransition

    + + + + + + + + + + + + + + + + + + + + + +
    ValorDescrição
    TefIPCarouselTransition.fadeDissolve entre imagens
    TefIPCarouselTransition.slideDesliza entre imagens
    TefIPCarouselTransition.noneTroca instantânea
    + + + + + + + + + + + + + + +
    + + + + + + + + + +
    + + -
    - - -
    -
    -
    - - - - - - - - - - - - - - +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/sdk-js/index.html b/site/sdk-js/index.html index 317dd50..2930081 100644 --- a/site/sdk-js/index.html +++ b/site/sdk-js/index.html @@ -1,1287 +1,1332 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - JavaScript - TEF IP Docs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - Pular para conteúdo - - -
    -
    - -
    - - - - -
    - - -
    - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  • - - - - - - - - - -
  • -
    -
    - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    - -
    - - -

    SDK JavaScript

    -

    Não existe pacote oficial JavaScript para o TEF IP neste momento.

    -

    Enquanto isso, a integração recomendada é chamar a API diretamente com fetch ou qualquer cliente HTTP equivalente, usando Basic Auth.

    -
    const res = await fetch('http://localhost:9050/status', {
    -  headers: {
    -    'Authorization': 'Basic ' + btoa('admin:1234'),
    -  },
    -});
    -
    -const data = await res.json();
    -
    -

    Os exemplos completos por endpoint estão nas páginas de API Reference. O panorama geral fica em SDKs.

    +
  • + + Guia de Integração + +
  • - -
    -
    - - - - -
    - -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - + + + + + + + + +
  • + + + + + API Reference + + +
  • + + + + + + + + + + + + + +
  • + + + + + SDKs + + +
  • + + + + + + + + + + + +
  • + + + + + Suporte e Operações + + +
  • + + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + +

    SDK JavaScript

    +

    Não existe pacote oficial JavaScript para o TEF IP neste momento.

    +

    Enquanto isso, a integração recomendada é chamar a API diretamente com fetch ou qualquer + cliente HTTP equivalente, usando Basic Auth.

    +
    +
    const res = await fetch('http://localhost:9050/status', {
    +  headers: {
    +    'Authorization': 'Basic ' + btoa('admin:1234'),
    +  },
    +});
    +
    +const data = await res.json();
    +
    +
    +

    Os exemplos completos por endpoint estão nas páginas de API Reference. + O panorama geral fica em SDKs.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + +
    + + + + +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/sdk-php/index.html b/site/sdk-php/index.html index d7f6450..852da65 100644 --- a/site/sdk-php/index.html +++ b/site/sdk-php/index.html @@ -1,1286 +1,1331 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - PHP - TEF IP Docs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - Pular para conteúdo - - -
    -
    - -
    - - - - -
    - - -
    - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  • - - - - - - - - - -
  • -
    -
    - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    - -
    - - -

    SDK PHP

    -

    Não existe pacote oficial PHP para o TEF IP neste momento.

    -

    Enquanto isso, a integração recomendada é chamar a API diretamente com curl ou outro cliente HTTP, usando Basic Auth.

    -
    <?php
    -$ch = curl_init('http://localhost:9050/status');
    -curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    -curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    -$response = json_decode(curl_exec($ch), true);
    -curl_close($ch);
    -
    -

    Os exemplos completos por endpoint estão nas páginas de API Reference. O panorama geral fica em SDKs.

    +
  • + + Guia de Integração + +
  • - -
    -
    - - - - -
    - -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - + + + + + + + + +
  • + + + + + API Reference + + +
  • + + + + + + + + + + + + + +
  • + + + + + SDKs + + +
  • + + + + + + + + + + + +
  • + + + + + Suporte e Operações + + +
  • + + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + +

    SDK PHP

    +

    Não existe pacote oficial PHP para o TEF IP neste momento.

    +

    Enquanto isso, a integração recomendada é chamar a API diretamente com curl ou outro cliente + HTTP, usando Basic Auth.

    +
    +
    <?php
    +$ch = curl_init('http://localhost:9050/status');
    +curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
    +curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    +$response = json_decode(curl_exec($ch), true);
    +curl_close($ch);
    +
    +
    +

    Os exemplos completos por endpoint estão nas páginas de API Reference. + O panorama geral fica em SDKs.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + +
    + + + + +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/sdk-ruby/index.html b/site/sdk-ruby/index.html index 724162a..068d988 100644 --- a/site/sdk-ruby/index.html +++ b/site/sdk-ruby/index.html @@ -1,1288 +1,1333 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - Ruby - TEF IP Docs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - Pular para conteúdo - - -
    -
    - -
    - - - - -
    - - -
    - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  • - - - - - - - - - -
  • -
    -
    - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    - -
    - - -

    SDK Ruby

    -

    Não existe pacote oficial Ruby para o TEF IP neste momento.

    -

    Enquanto isso, a integração recomendada é chamar a API diretamente com Net::HTTP ou outro cliente HTTP, usando Basic Auth.

    -
    require 'net/http'
    -require 'json'
    -
    -uri = URI('http://localhost:9050/status')
    -req = Net::HTTP::Get.new(uri)
    -req.basic_auth('admin', '1234')
    -res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }
    -data = JSON.parse(res.body)
    -
    -

    Os exemplos completos por endpoint estão nas páginas de API Reference. O panorama geral fica em SDKs.

    +
  • + + Guia de Integração + +
  • - -
    -
    - - - - -
    - -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - + + + + + + + + +
  • + + + + + API Reference + + +
  • + + + + + + + + + + + + + +
  • + + + + + SDKs + + +
  • + + + + + + + + + + + +
  • + + + + + Suporte e Operações + + +
  • + + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + +

    SDK Ruby

    +

    Não existe pacote oficial Ruby para o TEF IP neste momento.

    +

    Enquanto isso, a integração recomendada é chamar a API diretamente com Net::HTTP ou outro + cliente HTTP, usando Basic Auth.

    +
    +
    require 'net/http'
    +require 'json'
    +
    +uri = URI('http://localhost:9050/status')
    +req = Net::HTTP::Get.new(uri)
    +req.basic_auth('admin', '1234')
    +res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }
    +data = JSON.parse(res.body)
    +
    +
    +

    Os exemplos completos por endpoint estão nas páginas de API Reference. + O panorama geral fica em SDKs.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + +
    + + + + +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/sdks/index.html b/site/sdks/index.html index a08e7e0..9c7285e 100644 --- a/site/sdks/index.html +++ b/site/sdks/index.html @@ -1,1429 +1,1473 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - Visão geral - TEF IP Docs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - Pular para conteúdo - - -
    -
    - -
    - - - - -
    - - -
    - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  • - - - - - - - - - -
  • -
    -
    - - - -
    -
    -
    - - - -
    -
    -
    - - - -
    - -
    - - - - - -

    SDKs

    -

    Os SDKs do TEF IP são opcionais. A API continua sendo HTTP puro com Basic Auth, então qualquer linguagem pode integrar diretamente mesmo sem pacote dedicado.

    -
    -

    Panorama atual

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    LinguagemPacote oficialStatusDocumentação
    Dart / Flutterdart_tefipDisponívelSDK Dart
    JavaScriptNãoSem pacote oficial no momentoSDK JavaScript
    PHPNãoSem pacote oficial no momentoSDK PHP
    RubyNãoSem pacote oficial no momentoSDK Ruby
    -
    -

    Quando usar SDK

    - - - - - - - - - - - - - - - - - - - - - -
    CenárioRecomendação
    App Flutter ou DartUse o dart_tefip
    Backend ou PDV em outra linguagemUse HTTP direto
    Integração rápida ou prova de conceitoPode começar por cURL/fetch/curl/Net::HTTP
    -

    Todas as páginas de API Reference incluem exemplos prontos em cURL, Dart, JavaScript, PHP e Ruby.

    - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    - - - -
    -
    -
    -
    - - - - - - - - - - - - - - + + + + + + + + +
  • + + + + + Guia de Integração + + +
  • + + + + + + + + + + + +
  • + + + + + API Reference + + +
  • + + + + + + + + + + + + + +
  • + + + + + SDKs + + +
  • + + + + + + + + + + + +
  • + + + + + Suporte e Operações + + +
  • + + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + +

    SDKs

    +

    Os SDKs do TEF IP são opcionais. A API continua sendo HTTP puro com Basic Auth, então qualquer linguagem + pode integrar diretamente mesmo sem pacote dedicado.

    +
    +

    Panorama atual

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    LinguagemPacote oficialStatusDocumentação
    Dart / Flutterdart_tefipDisponívelSDK Dart
    JavaScriptNãoSem pacote oficial no momentoSDK JavaScript
    PHPNãoSem pacote oficial no momentoSDK PHP
    RubyNãoSem pacote oficial no momentoSDK Ruby
    +
    +

    Quando usar SDK

    + + + + + + + + + + + + + + + + + + + + + +
    CenárioRecomendação
    App Flutter ou DartUse o dart_tefip
    Backend ou PDV em outra linguagemUse HTTP direto
    Integração rápida ou prova de conceitoPode começar por cURL/fetch/curl/Net::HTTP
    +

    Todas as páginas de API Reference incluem exemplos prontos em + cURL, Dart, JavaScript, PHP e Ruby. +

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + +
    + + + + +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/search/search_index.json b/site/search/search_index.json index b9964e5..13250ca 100644 --- a/site/search/search_index.json +++ b/site/search/search_index.json @@ -1 +1,949 @@ -{"config":{"lang":["pt"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"TEF IP","text":"

    Aceite pagamentos com qualquer adquirente usando uma \u00fanica API HTTP local. Instale no terminal e comece a processar.

    "},{"location":"#como-funciona","title":"Como funciona","text":"
    flowchart LR\n    PDV[\"Seu sistema<br>(qualquer linguagem)\"]\n    tefip[\"TEF IP<br>IP Local\"]\n    HW[\"Adquirente\"]\n\n    PDV -- \"HTTP + Basic Auth\" --> tefip\n    tefip -- \"SDK do adquirente\" --> HW\n    HW -- \"aprova\u00e7\u00e3o / erro\" --> tefip\n    tefip -- \"JSON\" --> PDV

    Seu sistema faz chamadas HTTP para o TEF IP. O TEF IP se comunica com o hardware do adquirente e retorna o resultado em JSON, sem nenhuma SDK propriet\u00e1ria no seu lado.

    Sem maquininha? Use o emulador!

    O TEF IP inclui um modo emulador que simula o hardware do adquirente localmente. Voc\u00ea pode desenvolver e testar toda a integra\u00e7\u00e3o sem nenhum terminal f\u00edsico. Clique aqui para saber como usar o emulador

    Veja abaixo um pagamento sendo processado no emulador:

    "},{"location":"#o-que-voce-pode-fazer","title":"O que voc\u00ea pode fazer","text":""},{"location":"#integracao-rapida","title":"Integra\u00e7\u00e3o r\u00e1pida","text":"

    Qualquer cliente HTTP funciona. Veja um exemplo completo, um PIX de R$ 50,00, nas linguagens mais comuns:

    cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/transaction \\\n     -d '{\"tPag\":\"17\",\"amount\":50.00,\"referenceId\":\"pedido-001\"}'\n
    import 'package:dart_tefip/dart_tefip.dart';\n\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\n\nfinal result = await TefIP.instance.transaction.post(\n  transactionRequest: TransactionRequestModel(\n    type: TefIPTransactionType.pix,\n    amount: 50.00,\n    referenceId: 'pedido-001',\n  ),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/transaction', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ tPag: '17', amount: 50.00, referenceId: 'pedido-001' }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/transaction');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'tPag' => '17',\n    'amount' => 50.00,\n    'referenceId' => 'pedido-001',\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/transaction')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { 'tPag' => '17', amount: 50.00, referenceId: 'pedido-001' }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"#adquirentes-suportados","title":"Adquirentes suportados","text":"

    Cada build do TEF IP \u00e9 compilado para um adquirente espec\u00edfico.

    "},{"location":"#sdks-disponiveis","title":"SDKs dispon\u00edveis","text":"Linguagem Pacote Status Dart / Flutter dart_tefip Dispon\u00edvel JavaScript \u2014 Sem pacote oficial no momento PHP \u2014 Sem pacote oficial no momento Ruby \u2014 Sem pacote oficial no momento

    Qualquer cliente HTTP funciona diretamente; os SDKs s\u00e3o conveni\u00eancia, n\u00e3o requisito.

    "},{"location":"#proximos-passos","title":"Pr\u00f3ximos Passos","text":"

    Novo por aqui? Comece pelo guia:

    Primeiros Passos \u2192

    Instale o TEF IP, verifique a conex\u00e3o e fa\u00e7a sua primeira requisi\u00e7\u00e3o em menos de 10 minutos.

    "},{"location":"comportamento/","title":"Comportamento do Servidor","text":"

    Esta p\u00e1gina descreve como o TEF IP se comporta em situa\u00e7\u00f5es que afetam diretamente a sua integra\u00e7\u00e3o. Leia antes de implementar os endpoints \u2014 as decis\u00f5es aqui (especialmente sobre referenceId e o comportamento de servidor ocupado) determinam se sua integra\u00e7\u00e3o vai funcionar corretamente em produ\u00e7\u00e3o.

    Leitura obrigat\u00f3ria antes de integrar

    Desenvolvedores que pulam esta p\u00e1gina frequentemente descobrem em produ\u00e7\u00e3o que n\u00e3o conseguem estornar transa\u00e7\u00f5es (por falta de referenceId) ou n\u00e3o tratam corretamente o 503 de servidor ocupado.

    "},{"location":"comportamento/#fluxo-de-uma-transacao","title":"Fluxo de uma transa\u00e7\u00e3o","text":"

    Ao enviar um pagamento, o TEF IP repassa o comando ao terminal, que interage diretamente com o portador do cart\u00e3o ou exibe o QR Code do PIX. A resposta do servidor s\u00f3 chega quando o pagamento \u00e9 aprovado, recusado ou cancelado \u2014 o que pode levar v\u00e1rios segundos dependendo da rede e do adquirente.

    Durante esse tempo o servidor fica bloqueado: nenhuma outra opera\u00e7\u00e3o pode ser enviada at\u00e9 a transa\u00e7\u00e3o ser conclu\u00edda.

    Sequ\u00eancia:

    1. PDV envia POST /transaction
    2. TEF IP repassa ao terminal do adquirente
    3. Terminal processa (cliente insere cart\u00e3o, digita senha, confirma PIX\u2026)
    4. TEF IP retorna a resposta ao PDV
    5. PDV pode enviar a pr\u00f3xima opera\u00e7\u00e3o

    Tempo de resposta

    Dimensione o timeout do seu cliente HTTP para pelo menos 60 segundos \u2014 transa\u00e7\u00f5es com cart\u00e3o f\u00edsico dependem da intera\u00e7\u00e3o do cliente no terminal.

    "},{"location":"comportamento/#identificacao-de-transacoes","title":"Identifica\u00e7\u00e3o de transa\u00e7\u00f5es","text":"

    Para consultar ou estornar uma transa\u00e7\u00e3o depois, voc\u00ea precisa de um identificador que ligue o seu sistema ao TEF IP. Esse identificador \u2014 chamado de referenceId \u2014 \u00e9 informado pelo PDV no momento do pagamento.

    Use um identificador j\u00e1 existente no seu sistema \u2014 n\u00famero do pedido, UUID da venda \u2014 qualquer valor \u00fanico serve. O TEF IP armazena esse v\u00ednculo e o devolve na resposta.

    "},{"location":"comportamento/#fluxo-de-uma-venda","title":"Fluxo de uma venda","text":"

    Uma venda \u00e9 uma sess\u00e3o aberta que agrega itens e formas de pagamento antes de ser consolidada. Apenas uma venda pode estar ativa por vez \u2014 tentar abrir uma segunda enquanto h\u00e1 uma em aberto retorna 409.

    Venda e transa\u00e7\u00e3o s\u00e3o independentes

    A venda registra o qu\u00ea foi vendido e como foi pago \u2014 mas n\u00e3o processa o pagamento financeiro. O d\u00e9bito no cart\u00e3o ou PIX \u00e9 feito separadamente via POST /transaction.

    Veja o ciclo de vida completo e os endpoints de venda \u2192

    "},{"location":"comportamento/#cancelamento-de-item-vs-exclusao","title":"Cancelamento de item vs. exclus\u00e3o","text":"

    Ao remover um item de uma venda em aberto, voc\u00ea tem duas op\u00e7\u00f5es com comportamentos distintos:

    A\u00e7\u00e3o Resultado Excluir o item Item removido permanentemente \u2014 n\u00e3o aparece no cupom/NF Cancelar o item Item mantido no hist\u00f3rico como cancelado \u2014 consta no cupom/NF com status cancelado

    Use o cancelamento quando o item precisar aparecer no documento fiscal mesmo sem ser cobrado. Use a exclus\u00e3o quando o item foi adicionado por engano e n\u00e3o deve constar em nenhum documento.

    "},{"location":"comportamento/#coleta-de-dados-no-terminal","title":"Coleta de dados no terminal","text":"

    O TEF IP pode exibir perguntas no display do terminal (CPF, texto livre, listas, e-mail, CEP\u2026) e coletar respostas sem que o PDV precise de tela pr\u00f3pria. A conex\u00e3o HTTP fica aberta at\u00e9 o usu\u00e1rio confirmar ou cancelar.

    Veja os endpoints e tipos de campo dispon\u00edveis em Perguntas (Ask) \u2192

    "},{"location":"comportamento/#servidor-ocupado","title":"Servidor ocupado","text":"

    O TEF IP processa uma opera\u00e7\u00e3o por vez. Enquanto um pagamento, estorno ou impress\u00e3o est\u00e1 em andamento, o servidor recusa novas opera\u00e7\u00f5es.

    Opera\u00e7\u00f5es que bloqueiam o servidor:

    Endpoint Opera\u00e7\u00e3o POST /transaction Pagamento em processamento POST /transaction/{referenceId}/reversal Estorno em processamento POST /print/image Impress\u00e3o de imagem em andamento POST /print/text Impress\u00e3o de texto em andamento POST /print/xml Impress\u00e3o de XML em andamento

    O que acontece ao enviar uma requisi\u00e7\u00e3o durante esse per\u00edodo:

    {\n  \"code\": 503,\n  \"message\": \"Aplicativo ocupado realizando outra opera\u00e7\u00e3o, tente mais tarde!\"\n}\n

    Como verificar se o servidor est\u00e1 livre:

    Use GET /info para consultar o estado atual. Se o servidor estiver ocupado, aguarde antes de enviar uma nova opera\u00e7\u00e3o.

    Endpoints sempre dispon\u00edveis

    GET /status, GET /info e POST /restart respondem normalmente mesmo durante uma opera\u00e7\u00e3o \u2014 use-os para monitorar o estado do servidor.

    "},{"location":"comportamento/#app-em-segundo-plano","title":"App em segundo plano","text":"

    Pagamentos e estornos exigem que o TEF IP esteja vis\u00edvel na tela do terminal. Se o operador minimizou o app, o servidor aguarda automaticamente at\u00e9 15 segundos pelo retorno ao primeiro plano.

    O que acontece:

    1. O PDV envia POST /transaction ou POST /transaction/{referenceId}/reversal.
    2. O TEF IP detecta que est\u00e1 minimizado e aguarda at\u00e9 15 s.
    3. Se o app retornar ao primeiro plano dentro do prazo, a opera\u00e7\u00e3o prossegue normalmente.
    4. Se n\u00e3o retornar, o servidor rejeita a requisi\u00e7\u00e3o:
    {\n  \"code\": 503,\n  \"message\": \"Aplicativo em segundo plano. Abra o app para concluir o pagamento.\"\n}\n

    Notifica\u00e7\u00e3o autom\u00e1tica

    Ao receber o comando, o TEF IP envia uma notifica\u00e7\u00e3o ao operador pedindo para restaurar o aplicativo. Veja a se\u00e7\u00e3o Notifica\u00e7\u00f5es ao operador abaixo.

    Como verificar se o app est\u00e1 em primeiro plano:

    Use GET /info para consultar o estado atual do aplicativo.

    "},{"location":"comportamento/#notificacoes-ao-operador","title":"Notifica\u00e7\u00f5es ao operador","text":"

    Sempre que o TEF IP recebe um comando do PDV, ele exibe automaticamente uma notifica\u00e7\u00e3o no terminal alertando o operador para restaurar o aplicativo.

    Isso \u00e9 especialmente \u00fatil quando o operador minimizou o TEF IP \u2014 a notifica\u00e7\u00e3o serve como aviso para que o app volte ao primeiro plano antes do tempo limite de 15 segundos expirar.

    Nenhuma configura\u00e7\u00e3o \u00e9 necess\u00e1ria \u2014 o comportamento \u00e9 autom\u00e1tico.

    Se o seu fluxo precisar disparar um alerta manual fora desse comportamento autom\u00e1tico, use o endpoint Notifica\u00e7\u00f5es \u2192 POST /notification.

    "},{"location":"comportamento/#endpoints-sem-autenticacao","title":"Endpoints sem autentica\u00e7\u00e3o","text":"

    A maioria dos endpoints exige Basic Auth. As \u00fanicas exce\u00e7\u00f5es s\u00e3o:

    Endpoint Descri\u00e7\u00e3o GET /docs Swagger UI GET /openapi.bundle.yaml Especifica\u00e7\u00e3o OpenAPI

    Todos os demais endpoints exigem credenciais v\u00e1lidas. Requisi\u00e7\u00f5es sem autentica\u00e7\u00e3o ou com credenciais inv\u00e1lidas recebem 401.

    "},{"location":"comportamento/#cors","title":"CORS","text":"

    O TEF IP aceita requisi\u00e7\u00f5es de qualquer origem. Nenhuma configura\u00e7\u00e3o adicional \u00e9 necess\u00e1ria para clientes web ou browser:

    "},{"location":"comportamento/#respostas-de-erro","title":"Respostas de erro","text":"

    Todos os erros retornam { \"code\": <status>, \"message\": \"...\" }. Veja a Vis\u00e3o Geral de Erros \u2192 para a refer\u00eancia completa de c\u00f3digos HTTP e sugest\u00f5es de tratamento.

    "},{"location":"emulator/","title":"Emulador","text":"

    O TEF IP inclui um modo emulador que simula o hardware do adquirente localmente \u2014 sem precisar de nenhum terminal f\u00edsico. \u00c9 a forma mais r\u00e1pida de desenvolver e testar toda a integra\u00e7\u00e3o com o TEF IP.

    N\u00e3o usar em produ\u00e7\u00e3o

    O build com emulador \u00e9 destinado exclusivamente a desenvolvimento e testes. Para uso em produ\u00e7\u00e3o, utilize o app distribu\u00eddo pelo seu adquirente no terminal Android correspondente (Stone, Getnet ou Rede).

    Veja abaixo um pagamento sendo processado no emulador:

    "},{"location":"emulator/#download","title":"Download","text":"

    Escolha a plataforma para desenvolvimento e testes:

    Plataforma Arquivo Observa\u00e7\u00e3o Windows 10+ TEF IP-emulador-setup.exe Instalador com assistente; registra o TEF IP como servi\u00e7o do Windows Android (APK) TEF IP-emulador.apk Sideload manual; n\u00e3o dispon\u00edvel na Play Store

    Onde baixar

    Os arquivos de download s\u00e3o disponibilizados pelo canal TEF IP. Entre em contato com o suporte para obter o link de download da vers\u00e3o mais recente.

    "},{"location":"emulator/#instalacao-no-windows","title":"Instala\u00e7\u00e3o no Windows","text":"
    1. Execute o instalador TEF IP-emulador-setup.exe.
    2. Siga o assistente de instala\u00e7\u00e3o (pr\u00f3ximo \u2192 pr\u00f3ximo \u2192 instalar).
    3. Ao final, o TEF IP \u00e9 registrado como servi\u00e7o do Windows e inicia automaticamente com o sistema.
    4. Um \u00edcone aparecer\u00e1 na bandeja do sistema \u2014 clique nele para abrir o painel de controle.
    "},{"location":"emulator/#_1","title":"Testando com Emulador","text":""},{"location":"emulator/#instalacao-do-apk-android","title":"Instala\u00e7\u00e3o do APK Android","text":"
    1. No dispositivo Android, acesse Configura\u00e7\u00f5es \u2192 Seguran\u00e7a e habilite \"Fontes desconhecidas\" (ou \"Instalar apps desconhecidos\").
    2. Transfira o arquivo TEF IP-emulador.apk para o dispositivo (via USB, e-mail ou link direto).
    3. Toque no arquivo .apk para iniciar a instala\u00e7\u00e3o e confirme.
    4. Abra o app TEF IP ap\u00f3s a instala\u00e7\u00e3o.

    Dispositivo de testes

    Qualquer smartphone ou tablet Android com Android 8.0+ funciona para desenvolvimento. N\u00e3o \u00e9 necess\u00e1rio nenhum hardware de adquirente.

    "},{"location":"emulator/#proximos-passos","title":"Pr\u00f3ximos passos","text":"

    Dica de valida\u00e7\u00e3o r\u00e1pida

    Depois da instala\u00e7\u00e3o, valide o emulador com GET /status em http://localhost:9050/status usando Basic Auth. Se precisar investigar comportamento interno, consulte tamb\u00e9m Logs.

    "},{"location":"getting-started/","title":"Primeiros Passos","text":"

    Este guia leva voc\u00ea da instala\u00e7\u00e3o at\u00e9 a primeira resposta real do terminal de pagamento. Ao final, voc\u00ea ter\u00e1 o servidor rodando e confirmar\u00e1 que ele responde \u00e0s suas requisi\u00e7\u00f5es \u2014 pronto para come\u00e7ar a integrar os endpoints de pagamento.

    "},{"location":"getting-started/#pre-requisitos","title":"Pr\u00e9-requisitos","text":""},{"location":"getting-started/#instalacao","title":"Instala\u00e7\u00e3o","text":""},{"location":"getting-started/#terminais-android-adquirentes","title":"Terminais Android (Adquirentes)","text":"

    A instala\u00e7\u00e3o em terminais f\u00edsicos \u00e9 feita diretamente pela loja ou canal de distribui\u00e7\u00e3o do seu adquirente \u2014 o processo varia para cada um:

    Caso encontre alguma dificuldade, entre em contato com o nosso SUPORTE.

    "},{"location":"getting-started/#windows-emulador-desenvolvimentotestes","title":"Windows (Emulador \u2014 desenvolvimento/testes)","text":"
    1. Baixe o instalador .exe na p\u00e1gina do Emulador.
    2. Execute o instalador e siga o assistente de instala\u00e7\u00e3o.
    3. Ao final, o TEF IP ser\u00e1 registrado como servi\u00e7o do Windows e iniciar\u00e1 automaticamente.

    Build com emulador

    O instalador Windows dispon\u00edvel nas releases inclui o emulador de hardware \u2014 ideal para desenvolvimento e testes sem terminal f\u00edsico. Para uso em produ\u00e7\u00e3o, utilize o app distribu\u00eddo pelo seu adquirente no terminal Android correspondente.

    "},{"location":"getting-started/#emulador-apk-android-emulador-desenvolvimentotestes","title":"Emulador (APK Android) (Emulador \u2014 desenvolvimento/testes)","text":"

    O APK Android dispon\u00edvel na p\u00e1gina do Emulador \u00e9 o build com emulador de hardware \u2014 destinado a desenvolvimento e testes sem terminal f\u00edsico.

    N\u00e3o usar em produ\u00e7\u00e3o

    Este APK n\u00e3o deve ser instalado em terminais f\u00edsicos de produ\u00e7\u00e3o (Stone, Getnet, Rede). Para terminais f\u00edsicos, obtenha o app pelo canal do seu adquirente conforme descrito acima.

    "},{"location":"getting-started/#iniciando-o-servidor","title":"Iniciando o servidor","text":"

    Se for o primeiro acesso, a inicializa\u00e7\u00e3o autom\u00e1tica j\u00e1 estar\u00e1 ativa.

    Para verificar os servidores ativos:

    1. Abra o aplicativo TEF IP no terminal.
    2. Acesse a se\u00e7\u00e3o Servidores na tela inicial.
    3. Se n\u00e3o aparecer na tela inicial, abra o menu \u2192 Configura\u00e7\u00f5es \u2192 Servidores.

    Nessa tela \u00e9 poss\u00edvel visualizar os IPs detectados e executar a\u00e7\u00f5es como reiniciar ou parar os servi\u00e7os.

    "},{"location":"getting-started/#verificando-a-conexao","title":"Verificando a conex\u00e3o","text":"

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o). Os \u00fanicos endpoints sem autentica\u00e7\u00e3o s\u00e3o /docs e /openapi.bundle.yaml.

    Use o endpoint GET /status para confirmar que o servidor est\u00e1 respondendo:

    cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     http://localhost:9050/status\n
    import 'package:dart_tefip/dart_tefip.dart';\n\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\n\nfinal status = await TefIP.instance.status.get();\nprint(status);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/status', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\nconsole.log(data);\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/status');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\nprint_r($response);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/status')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\nputs data\n

    Resposta esperada:

    {\n  \"status\": \"ok\",\n  \"uptimeSeconds\": 144,\n  \"startedAt\": \"2026-01-28T16:20:53.223883\"\n}\n
    "},{"location":"getting-started/#proximos-passos","title":"Pr\u00f3ximos passos","text":"

    Com o servidor respondendo, o caminho natural \u00e9:

    1. Comportamento \u2014 entenda como o servidor lida com opera\u00e7\u00f5es simult\u00e2neas, app em segundo plano e autentica\u00e7\u00e3o antes de integrar os endpoints.
    2. Transa\u00e7\u00f5es \u2014 processe pagamentos e estornos.
    3. Vendas \u2014 monte carrinho com itens e m\u00faltiplas formas de pagamento.
    4. Swagger UI \u2014 explore e teste todos os endpoints diretamente no terminal.
    "},{"location":"sdk-dart/","title":"SDK Dart","text":"

    O dart_tefip \u00e9 o SDK oficial para Dart e Flutter. Ele encapsula as chamadas HTTP do TEF IP com modelos tipados, serializa\u00e7\u00e3o de payloads e exce\u00e7\u00f5es espec\u00edficas para a API.

    "},{"location":"sdk-dart/#instalacao","title":"Instala\u00e7\u00e3o","text":"

    Adicione ao seu pubspec.yaml:

    dependencies:\n  dart_tefip: ^<vers\u00e3o>\n

    Depois execute:

    dart pub get\n# ou\nflutter pub get\n
    "},{"location":"sdk-dart/#configuracao","title":"Configura\u00e7\u00e3o","text":"

    O SDK usa o padr\u00e3o singleton com setters est\u00e1ticos:

    import 'package:dart_tefip/dart_tefip.dart';\n\nTefIP.baseUrl = 'http://192.168.1.10:9050';\nTefIP.username = 'admin';\nTefIP.password = 'minha-senha';\n

    Para desenvolvimento local com o emulador:

    TefIP.baseUrl = 'http://localhost:9050';\n

    TefIPClient n\u00e3o existe

    N\u00e3o existe nenhuma classe TefIPClient no SDK. Use sempre TefIP.instance.

    "},{"location":"sdk-dart/#chamando-endpoints","title":"Chamando endpoints","text":"

    Todos os endpoints ficam dispon\u00edveis via TefIP.instance.<grupo>.<m\u00e9todo>(...):

    final result = await TefIP.instance.transaction.post(\n  transactionRequest: TransactionRequestModel(\n    type: TefIPTransactionType.pix,\n    amount: 50.00,\n    referenceId: 'pedido-001',\n  ),\n);\n\nprint(result.nsu);\nprint(result.txid); // PIX\nprint(result.cAut); // cr\u00e9dito/d\u00e9bito\n
    "},{"location":"sdk-dart/#catalogo-de-metodos","title":"Cat\u00e1logo de m\u00e9todos","text":"Grupo M\u00e9todos dispon\u00edveis transaction getAll(), get(referenceId:), post(transactionRequest:) reversal post(referenceId:) status get() info get() restart post() sale get(), post(request:), patch(request:), clear() saleItem post(item:), patch(itemId:, item:), delete(itemId:), cancel(itemId:), clear() salePayment post(payment:), patch(paymentId:, payment:), delete(paymentId:), clear() saleDiscount post(discount:), patch(discountId:, discount:), delete(discountId:), clear() saleAddition post(addition:), patch(additionId:, addition:), delete(additionId:), clear() saleFinalize post(), post(params:) saleCancel post(), post(params:) ask post(questionRequest:) askForm post(form:) askCancel post() displayImage post(imageData:) displayText post(displayTextRequest:) displayCarousel post(displayCarouselRequest:) displayClear post() displayPop post() printImage post(imageData:) printText post(text:) printXml post(xml:) log getAll(level:, source:, dateFrom:, dateTo:, limit:, search:, includeDetails:), stream(), downloadZip(level:, source:, dateFrom:, dateTo:, limit:) notification post(request:)

    Sem accessor para ACBr

    O SDK Dart atual n\u00e3o exp\u00f5e um m\u00e9todo dedicado para POST /print/acbr. Para esse endpoint, use HTTP direto.

    "},{"location":"sdk-dart/#exemplos-rapidos","title":"Exemplos r\u00e1pidos","text":""},{"location":"sdk-dart/#venda","title":"Venda","text":"
    await TefIP.instance.sale.post(\n  request: SaleStartRequestModel(\n    customerName: 'Jo\u00e3o Silva',\n    total: 99.90,\n  ),\n);\n\nawait TefIP.instance.saleItem.post(\n  item: SaleItemModel(\n    code: '123',\n    description: 'Coca-Cola 2L',\n    quantity: 1,\n    unitPrice: 10.00,\n  ),\n);\n
    "},{"location":"sdk-dart/#ask","title":"Ask","text":"
    final answer = await TefIP.instance.ask.post(\n  questionRequest: AskSingleQuestionRequestModel(\n    question: AskQuestionModel(type: TefIPQuestionType.cpfOrcnpj),\n    parameters: AskParametersModel(),\n  ),\n);\n\nprint(answer.value);\n
    "},{"location":"sdk-dart/#display","title":"Display","text":"
    await TefIP.instance.displayText.post(\n  displayTextRequest: DisplayTextRequestModel(\n    content: [\n      {'text': 'Aguardando operador'},\n    ],\n    backgroundColor: 'white',\n    showCloseButton: false,\n  ),\n);\n
    "},{"location":"sdk-dart/#logs","title":"Logs","text":"
    final logs = await TefIP.instance.log.getAll(\n  level: TefIPLogLevel.error,\n  limit: 50,\n);\n\nTefIP.instance.log.stream().listen((log) {\n  print('[${log.level.name}] ${log.message}');\n});\n
    "},{"location":"sdk-dart/#notificacoes","title":"Notifica\u00e7\u00f5es","text":"
    await TefIP.instance.notification.post(\n  request: NotificationRequestModel(\n    title: 'Novo pagamento',\n    message: 'Restaure o aplicativo para processar',\n  ),\n);\n
    "},{"location":"sdk-dart/#timeout","title":"Timeout","text":"

    Por padr\u00e3o, o SDK n\u00e3o define timeout global. Isso \u00e9 \u00fatil para fluxos de pagamento em que o terminal pode aguardar intera\u00e7\u00e3o do operador ou do cliente por tempo indeterminado.

    Para definir um timeout global:

    TefIP.requestsTimeOut = const Duration(minutes: 2);\n

    Tamb\u00e9m \u00e9 poss\u00edvel passar timeout: em chamadas que suportam override por requisi\u00e7\u00e3o.

    "},{"location":"sdk-dart/#tratamento-de-excecoes","title":"Tratamento de exce\u00e7\u00f5es","text":"

    Todo m\u00e9todo do SDK pode lan\u00e7ar dois tipos de exce\u00e7\u00e3o:

    try {\n  final result = await TefIP.instance.transaction.post(\n    transactionRequest: TransactionRequestModel(\n      type: TefIPTransactionType.pix,\n      amount: 50.00,\n    ),\n  );\n  print(result.nsu);\n} on TefIPRequestException catch (e) {\n  print(e.statusCode);\n  print(e.message);\n  print(e.rawBody);\n} on TefIPUnexpectedException catch (e) {\n  print(e.exception);\n}\n
    Exce\u00e7\u00e3o Quando ocorre Campos TefIPRequestException API retornou 4xx/5xx ou falha de conex\u00e3o tratada statusCode, message, rawBody? TefIPUnexpectedException Erro inesperado fora do fluxo HTTP padr\u00e3o exception"},{"location":"sdk-dart/#referencia-de-enums","title":"Refer\u00eancia de enums","text":""},{"location":"sdk-dart/#tefiptransactiontype","title":"TefIPTransactionType","text":"Valor tPag Descri\u00e7\u00e3o TefIPTransactionType.money \"01\" Dinheiro TefIPTransactionType.credit \"03\" Cr\u00e9dito TefIPTransactionType.debit \"04\" D\u00e9bito TefIPTransactionType.pix \"17\" PIX TefIPTransactionType.unknown \"99\" Desconhecido"},{"location":"sdk-dart/#tefipinstallmenttype","title":"TefIPInstallmentType","text":"Valor Descri\u00e7\u00e3o TefIPInstallmentType.single \u00c0 vista TefIPInstallmentType.seller Parcelado pelo lojista TefIPInstallmentType.buyer Parcelado pelo comprador"},{"location":"sdk-dart/#tefiptransactionstatus","title":"TefIPTransactionStatus","text":"Valor Descri\u00e7\u00e3o TefIPTransactionStatus.pending Pendente TefIPTransactionStatus.paid Pago TefIPTransactionStatus.cancelled Cancelado TefIPTransactionStatus.unknown Desconhecido"},{"location":"sdk-dart/#tefipsalepaymenttype","title":"TefIPSalePaymentType","text":"Valor Descri\u00e7\u00e3o TefIPSalePaymentType.money Dinheiro TefIPSalePaymentType.credit Cr\u00e9dito TefIPSalePaymentType.debit D\u00e9bito TefIPSalePaymentType.gift Cart\u00e3o-presente TefIPSalePaymentType.pix PIX TefIPSalePaymentType.veroWallet Carteira digital Vero TefIPSalePaymentType.voucher Voucher TefIPSalePaymentType.adm Opera\u00e7\u00e3o administrativa TefIPSalePaymentType.cancel Cancelamento de pagamento TefIPSalePaymentType.cancelDigitalWallet Cancelamento de carteira digital TefIPSalePaymentType.unknown Desconhecido"},{"location":"sdk-dart/#tefipquestiontype","title":"TefIPQuestionType","text":"Valor Descri\u00e7\u00e3o TefIPQuestionType.list Lista de op\u00e7\u00f5es TefIPQuestionType.button Bot\u00f5es de op\u00e7\u00e3o TefIPQuestionType.text Texto livre TefIPQuestionType.phone Telefone TefIPQuestionType.number Somente n\u00fameros TefIPQuestionType.cpf CPF TefIPQuestionType.cnpj CNPJ TefIPQuestionType.cpfOrcnpj CPF ou CNPJ TefIPQuestionType.email E-mail TefIPQuestionType.cep CEP TefIPQuestionType.date Data TefIPQuestionType.time Hora TefIPQuestionType.money Valor monet\u00e1rio TefIPQuestionType.regex Regex personalizada"},{"location":"sdk-dart/#tefipcarouseltransition","title":"TefIPCarouselTransition","text":"Valor Descri\u00e7\u00e3o TefIPCarouselTransition.fade Dissolve entre imagens TefIPCarouselTransition.slide Desliza entre imagens TefIPCarouselTransition.none Troca instant\u00e2nea"},{"location":"sdk-js/","title":"SDK JavaScript","text":"

    N\u00e3o existe pacote oficial JavaScript para o TEF IP neste momento.

    Enquanto isso, a integra\u00e7\u00e3o recomendada \u00e9 chamar a API diretamente com fetch ou qualquer cliente HTTP equivalente, usando Basic Auth.

    const res = await fetch('http://localhost:9050/status', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\n\nconst data = await res.json();\n

    Os exemplos completos por endpoint est\u00e3o nas p\u00e1ginas de API Reference. O panorama geral fica em SDKs.

    "},{"location":"sdk-php/","title":"SDK PHP","text":"

    N\u00e3o existe pacote oficial PHP para o TEF IP neste momento.

    Enquanto isso, a integra\u00e7\u00e3o recomendada \u00e9 chamar a API diretamente com curl ou outro cliente HTTP, usando Basic Auth.

    <?php\n$ch = curl_init('http://localhost:9050/status');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n

    Os exemplos completos por endpoint est\u00e3o nas p\u00e1ginas de API Reference. O panorama geral fica em SDKs.

    "},{"location":"sdk-ruby/","title":"SDK Ruby","text":"

    N\u00e3o existe pacote oficial Ruby para o TEF IP neste momento.

    Enquanto isso, a integra\u00e7\u00e3o recomendada \u00e9 chamar a API diretamente com Net::HTTP ou outro cliente HTTP, usando Basic Auth.

    require 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/status')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n

    Os exemplos completos por endpoint est\u00e3o nas p\u00e1ginas de API Reference. O panorama geral fica em SDKs.

    "},{"location":"sdks/","title":"SDKs","text":"

    Os SDKs do TEF IP s\u00e3o opcionais. A API continua sendo HTTP puro com Basic Auth, ent\u00e3o qualquer linguagem pode integrar diretamente mesmo sem pacote dedicado.

    "},{"location":"sdks/#panorama-atual","title":"Panorama atual","text":"Linguagem Pacote oficial Status Documenta\u00e7\u00e3o Dart / Flutter dart_tefip Dispon\u00edvel SDK Dart JavaScript N\u00e3o Sem pacote oficial no momento SDK JavaScript PHP N\u00e3o Sem pacote oficial no momento SDK PHP Ruby N\u00e3o Sem pacote oficial no momento SDK Ruby"},{"location":"sdks/#quando-usar-sdk","title":"Quando usar SDK","text":"Cen\u00e1rio Recomenda\u00e7\u00e3o App Flutter ou Dart Use o dart_tefip Backend ou PDV em outra linguagem Use HTTP direto Integra\u00e7\u00e3o r\u00e1pida ou prova de conceito Pode come\u00e7ar por cURL/fetch/curl/Net::HTTP

    Todas as p\u00e1ginas de API Reference incluem exemplos prontos em cURL, Dart, JavaScript, PHP e Ruby.

    "},{"location":"api/ask/","title":"Perguntas (Ask)","text":"

    Endpoints para exibir perguntas interativas na tela do terminal e coletar respostas do cliente \u2014 CPF, e-mail, texto livre, listas de op\u00e7\u00f5es e muito mais.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    "},{"location":"api/ask/#como-funciona","title":"Como funciona","text":"

    A requisi\u00e7\u00e3o HTTP fica aberta at\u00e9 o usu\u00e1rio confirmar ou cancelar no terminal \u2014 ou o PDV enviar POST /ask/cancel. Use Pergunta \u00danica (/ask) para campos avulsos e Formul\u00e1rio (/ask/form) para coletar v\u00e1rios campos em sequ\u00eancia; as respostas chegam todas juntas ao final.

    Timeout

    Configure o timeout do cliente para pelo menos 60 segundos, pois a resposta depende da intera\u00e7\u00e3o humana no terminal.

    "},{"location":"api/ask/#post-ask","title":"POST /ask","text":"

    Exibe uma \u00fanica pergunta na tela do terminal e aguarda a resposta do cliente.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"parameters\": {\n    \"buttonText\": \"Confirmar\",\n    \"showCancelButton\": false,\n    \"buttonCancelText\": \"Cancelar\",\n    \"showSuccessMessage\": false,\n    \"successMessage\": null,\n    \"successMessageInterval\": 3000,\n    \"confirmAnswer\": false\n  },\n  \"question\": {\n    \"id\": 0,\n    \"question\": \"Informe seu CPF\",\n    \"type\": \"CPF\",\n    \"required\": false,\n    \"minLength\": 0,\n    \"maxLength\": 255,\n    \"defaultValue\": null,\n    \"mask\": null,\n    \"regex\": null,\n    \"errorMessage\": null,\n    \"options\": null\n  }\n}\n

    Campos de parameters

    Campo Tipo Padr\u00e3o Descri\u00e7\u00e3o buttonText string \"Confirmar\" Texto do bot\u00e3o de confirma\u00e7\u00e3o showCancelButton bool false Exibe bot\u00e3o de cancelamento buttonCancelText string \"Cancelar\" Texto do bot\u00e3o de cancelamento showSuccessMessage bool false Exibe tela de sucesso ap\u00f3s confirma\u00e7\u00e3o successMessage string null Mensagem de sucesso personalizada successMessageInterval int 3000 Dura\u00e7\u00e3o (ms) da tela de sucesso confirmAnswer bool false Exige confirma\u00e7\u00e3o antes de submeter a resposta

    Campos de question

    Campo Tipo Padr\u00e3o Descri\u00e7\u00e3o id int 0 Identificador da pergunta question string null Texto exibido na tela (se null, usa prompt padr\u00e3o do tipo) type string \"TEXT\" Tipo de entrada (ver tabela abaixo) required bool false Resposta obrigat\u00f3ria minLength int 0 Comprimento m\u00ednimo da resposta maxLength int 255 Comprimento m\u00e1ximo da resposta defaultValue string null Valor pr\u00e9-preenchido no campo mask string null M\u00e1scara de entrada (ex.: \"###.###.###-##\") regex string null Regex de valida\u00e7\u00e3o personalizado errorMessage string null Mensagem de erro quando a valida\u00e7\u00e3o falha options array null Op\u00e7\u00f5es selecion\u00e1veis (obrigat\u00f3rio para LIST e BUTTON)

    Tipos de entrada (type)

    Valor Descri\u00e7\u00e3o \"TEXT\" Texto livre \"NUMBER\" Somente n\u00fameros \"PHONE\" N\u00famero de telefone \"CPF\" CPF (com valida\u00e7\u00e3o) \"CNPJ\" CNPJ (com valida\u00e7\u00e3o) \"CPFORCNPJ\" CPF ou CNPJ \"EMAIL\" E-mail (com valida\u00e7\u00e3o) \"CEP\" CEP (com valida\u00e7\u00e3o) \"DATE\" Data \"TIME\" Hora \"MONEY\" Valor monet\u00e1rio \"REGEX\" Valida\u00e7\u00e3o por regex personalizado \"LIST\" Lista de op\u00e7\u00f5es (requer options) \"BUTTON\" Bot\u00f5es de op\u00e7\u00e3o (requer options)

    Formato de options (obrigat\u00f3rio para LIST e BUTTON)

    [\n  { \"id\": 1, \"name\": \"Sim\", \"value\": \"sim\" },\n  { \"id\": 2, \"name\": \"N\u00e3o\", \"value\": \"nao\" }\n]\n
    Campo Tipo Descri\u00e7\u00e3o id int Identificador \u00fanico da op\u00e7\u00e3o name string Texto exibido na tela value string Valor retornado quando a op\u00e7\u00e3o \u00e9 selecionada

    Resposta \u2014 200

    {\n  \"id\": 0,\n  \"value\": \"12345678900\"\n}\n
    Campo Tipo Descri\u00e7\u00e3o id int Identificador da pergunta respondida value string Resposta fornecida pelo cliente"},{"location":"api/ask/#exemplos-de-integracao","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/ask \\\n     -d '{\n       \"parameters\": { \"buttonText\": \"Confirmar\" },\n       \"question\": { \"type\": \"CPF\", \"question\": \"Informe seu CPF\" }\n     }'\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal answer = await TefIP.instance.ask.post(\n  questionRequest: AskSingleQuestionRequestModel(\n    parameters: AskParametersModel(buttonText: 'Confirmar'),\n    question: AskQuestionModel(\n      question: 'Informe seu CPF',\n      type: TefIPQuestionType.cpf,\n    ),\n  ),\n);\nprint(answer.value);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/ask', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    parameters: { buttonText: 'Confirmar' },\n    question: { type: 'CPF', question: 'Informe seu CPF' },\n  }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/ask');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'parameters' => ['buttonText' => 'Confirmar'],\n    'question'   => ['type' => 'CPF', 'question' => 'Informe seu CPF'],\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/ask')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = {\n  parameters: { buttonText: 'Confirmar' },\n  question: { type: 'CPF', question: 'Informe seu CPF' },\n}.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/ask/#post-askform","title":"POST /ask/form","text":"

    Exibe um formul\u00e1rio com m\u00faltiplas perguntas em sequ\u00eancia. O cliente responde cada uma antes de passar para a pr\u00f3xima.

    IDs autom\u00e1ticos

    Se todas as perguntas tiverem id: 0, o TEF IP atribui IDs sequenciais automaticamente (0, 1, 2\u2026). Se quiser IDs personalizados, cada pergunta deve ter um id \u00fanico \u2014 duplicatas retornam 400.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"parameters\": {\n    \"buttonText\": \"Pr\u00f3ximo\",\n    \"showCancelButton\": true,\n    \"buttonCancelText\": \"Cancelar\"\n  },\n  \"questions\": [\n    {\n      \"id\": 1,\n      \"question\": \"Nome completo\",\n      \"type\": \"TEXT\",\n      \"required\": true\n    },\n    {\n      \"id\": 2,\n      \"question\": \"CPF\",\n      \"type\": \"CPF\",\n      \"required\": true\n    },\n    {\n      \"id\": 3,\n      \"question\": \"Como prefere pagar?\",\n      \"type\": \"LIST\",\n      \"options\": [\n        { \"id\": 1, \"name\": \"Cr\u00e9dito\", \"value\": \"credit\" },\n        { \"id\": 2, \"name\": \"D\u00e9bito\",  \"value\": \"debit\"  },\n        { \"id\": 3, \"name\": \"PIX\",     \"value\": \"pix\"    }\n      ]\n    }\n  ]\n}\n

    Resposta \u2014 200

    Array com a resposta de cada pergunta, na mesma ordem.

    [\n  { \"id\": 1, \"value\": \"Jo\u00e3o Silva\" },\n  { \"id\": 2, \"value\": \"12345678900\" },\n  { \"id\": 3, \"value\": \"pix\" }\n]\n

    Resposta \u2014 400

    { \"code\": 400, \"message\": \"Nenhuma pergunta recebida\" }\n
    { \"code\": 400, \"message\": \"Existem perguntas com IDs duplicados no formul\u00e1rio\" }\n

    "},{"location":"api/ask/#exemplos-de-integracao_1","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/ask/form \\\n     -d '{\n       \"parameters\": { \"buttonText\": \"Pr\u00f3ximo\" },\n       \"questions\": [\n         { \"id\": 1, \"question\": \"Nome\", \"type\": \"TEXT\" },\n         { \"id\": 2, \"question\": \"CPF\",  \"type\": \"CPF\"  }\n       ]\n     }'\n
    final answers = await TefIP.instance.askForm.post(\n  form: AskFormRequestModel(\n    parameters: AskParametersModel(buttonText: 'Pr\u00f3ximo'),\n    questions: [\n      AskQuestionModel(id: 1, question: 'Nome', type: TefIPQuestionType.text),\n      AskQuestionModel(id: 2, question: 'CPF',  type: TefIPQuestionType.cpf),\n    ],\n  ),\n);\nfor (final a in answers) {\n  print('${a.id}: ${a.value}');\n}\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/ask/form', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    parameters: { buttonText: 'Pr\u00f3ximo' },\n    questions: [\n      { id: 1, question: 'Nome', type: 'TEXT' },\n      { id: 2, question: 'CPF',  type: 'CPF'  },\n    ],\n  }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/ask/form');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'parameters' => ['buttonText' => 'Pr\u00f3ximo'],\n    'questions'  => [\n        ['id' => 1, 'question' => 'Nome', 'type' => 'TEXT'],\n        ['id' => 2, 'question' => 'CPF',  'type' => 'CPF' ],\n    ],\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/ask/form')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = {\n  parameters: { buttonText: 'Pr\u00f3ximo' },\n  questions: [\n    { id: 1, question: 'Nome', type: 'TEXT' },\n    { id: 2, question: 'CPF',  type: 'CPF'  },\n  ],\n}.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/ask/#post-askcancel","title":"POST /ask/cancel","text":"

    Cancela a pergunta ou formul\u00e1rio em exibi\u00e7\u00e3o no momento.

    N\u00e3o h\u00e1 corpo na requisi\u00e7\u00e3o.

    Resposta \u2014 200

    {\n  \"message\": \"Pergunta cancelada com sucesso\"\n}\n
    "},{"location":"api/ask/#exemplos-de-integracao_2","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/ask/cancel\n
    await TefIP.instance.askCancel.post();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/ask/cancel', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/ask/cancel');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/ask/cancel')\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/display/","title":"Display","text":"

    Endpoints para controlar a tela do terminal \u2014 exibir imagens, textos formatados, carross\u00e9is e limpar o display.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    "},{"location":"api/display/#quando-usar-o-display","title":"Quando usar o display","text":"

    O display \u00e9 um canal independente do fluxo de pagamento \u2014 exibir conte\u00fado n\u00e3o bloqueia nem interfere com transa\u00e7\u00f5es. Use-o para comunica\u00e7\u00e3o visual com o cliente:

    Ao finalizar ou cancelar uma venda (POST /sale/finalize / POST /sale/cancel), o TEF IP limpa o display automaticamente.

    "},{"location":"api/display/#post-displayimage","title":"POST /display/image","text":"

    Exibe uma imagem em tela cheia na tela do terminal.

    Corpo da requisi\u00e7\u00e3o

    Bytes bin\u00e1rios da imagem, enviados diretamente no corpo da requisi\u00e7\u00e3o.

    Header Valor Content-Type application/octet-stream

    Resposta \u2014 200

    { \"message\": \"Imagem exibida com sucesso\" }\n

    Resposta \u2014 400 (nenhuma imagem enviada)

    { \"code\": 400, \"message\": \"Nenhuma imagem enviada\" }\n

    Resposta \u2014 500 (erro ao exibir)

    { \"code\": 500, \"message\": \"Erro ao exibir imagem\" }\n
    "},{"location":"api/display/#exemplos-de-integracao","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/octet-stream\" \\\n     -X POST http://localhost:9050/display/image \\\n     --data-binary @imagem.png\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nimport 'dart:io';\n\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal imageData = await File('imagem.png').readAsBytes();\nawait TefIP.instance.displayImage.post(imageData: imageData);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst imageBytes = await fetch('/imagem.png').then(r => r.arrayBuffer());\nconst res = await fetch('http://localhost:9050/display/image', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/octet-stream',\n  },\n  body: imageBytes,\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$imageData = file_get_contents('imagem.png');\n$ch = curl_init('http://localhost:9050/display/image');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/octet-stream']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, $imageData);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nimage_data = File.binread('imagem.png')\nuri = URI('http://localhost:9050/display/image')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/octet-stream')\nreq.basic_auth('admin', '1234')\nreq.body = image_data\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/display/#post-displaytext","title":"POST /display/text","text":"

    Exibe conte\u00fado de texto formatado na tela do terminal.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"content\": [\n    { \"text\": { \"value\": \"Bem-vindo!\", \"size\": 24, \"bold\": true, \"align\": \"center\" } },\n    { \"line\": { \"divider\": true } },\n    { \"text\": { \"value\": \"Aguarde o atendimento.\", \"size\": 16, \"align\": \"center\" } }\n  ],\n  \"backgroundColor\": \"#FFFFFF\",\n  \"showCloseButton\": true\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o content array Sim Instru\u00e7\u00f5es de layout (ver formato abaixo) backgroundColor string N\u00e3o Cor de fundo em hex (padr\u00e3o: \"#FFFFFF\") showCloseButton bool N\u00e3o Exibe bot\u00e3o para fechar a tela

    Formato de content

    Cada item do array \u00e9 um objeto com uma chave identificando o tipo de elemento:

    Tipo Exemplo Texto { \"text\": { \"value\": \"Ol\u00e1\", \"size\": 18, \"bold\": false, \"align\": \"left\" } } Divisor { \"line\": { \"divider\": true } }

    Resposta \u2014 200

    { \"message\": \"Texto exibido com sucesso\" }\n
    "},{"location":"api/display/#exemplos-de-integracao_1","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/display/text \\\n     -d '{\n       \"content\": [\n         { \"text\": { \"value\": \"Bem-vindo!\", \"size\": 24, \"bold\": true, \"align\": \"center\" } }\n       ],\n       \"backgroundColor\": \"#FFFFFF\",\n       \"showCloseButton\": true\n     }'\n
    await TefIP.instance.displayText.post(\n  displayTextRequest: DisplayTextRequestModel(\n    content: [\n      {'text': {'value': 'Bem-vindo!', 'size': 24, 'bold': true, 'align': 'center'}},\n    ],\n    backgroundColor: '#FFFFFF',\n    showCloseButton: true,\n  ),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/display/text', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    content: [\n      { text: { value: 'Bem-vindo!', size: 24, bold: true, align: 'center' } },\n    ],\n    backgroundColor: '#FFFFFF',\n    showCloseButton: true,\n  }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/display/text');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'content' => [\n        ['text' => ['value' => 'Bem-vindo!', 'size' => 24, 'bold' => true, 'align' => 'center']],\n    ],\n    'backgroundColor' => '#FFFFFF',\n    'showCloseButton' => true,\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/display/text')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = {\n  content: [\n    { text: { value: 'Bem-vindo!', size: 24, bold: true, align: 'center' } },\n  ],\n  backgroundColor: '#FFFFFF',\n  showCloseButton: true,\n}.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/display/#post-displaycarousel","title":"POST /display/carousel","text":"

    Exibe um carrossel de imagens na tela do terminal, alternando automaticamente em intervalos configur\u00e1veis.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"images\": [\n    \"<base64 da imagem 1>\",\n    \"<base64 da imagem 2>\"\n  ],\n  \"intervalMs\": 3000,\n  \"transition\": \"fade\",\n  \"backgroundColor\": \"#000000\",\n  \"showCloseButton\": false\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o images array de string Sim Imagens em Base64 (pelo menos uma) intervalMs int N\u00e3o Intervalo entre imagens em ms (padr\u00e3o: 3000) transition string N\u00e3o Anima\u00e7\u00e3o de transi\u00e7\u00e3o (padr\u00e3o: \"fade\") backgroundColor string N\u00e3o Cor de fundo em hex (padr\u00e3o: \"#FFFFFF\") showCloseButton bool N\u00e3o Exibe bot\u00e3o para fechar (padr\u00e3o: false)

    Valores de transition

    Valor Descri\u00e7\u00e3o \"fade\" Transi\u00e7\u00e3o por dissolu\u00e7\u00e3o (padr\u00e3o) \"slide\" Transi\u00e7\u00e3o por deslizamento \"none\" Sem anima\u00e7\u00e3o de transi\u00e7\u00e3o

    Resposta \u2014 200

    { \"message\": \"Carousel exibido com sucesso\" }\n
    "},{"location":"api/display/#exemplos-de-integracao_2","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    # Converta as imagens para Base64 antes de enviar\nIMG1=$(base64 -w 0 imagem1.png)\nIMG2=$(base64 -w 0 imagem2.png)\n\ncurl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/display/carousel \\\n     -d \"{\\\"images\\\":[\\\"$IMG1\\\",\\\"$IMG2\\\"],\\\"intervalMs\\\":3000,\\\"transition\\\":\\\"fade\\\",\\\"backgroundColor\\\":\\\"#000000\\\"}\"\n
    import 'dart:io';\n\nfinal img1 = await File('imagem1.png').readAsBytes();\nfinal img2 = await File('imagem2.png').readAsBytes();\nawait TefIP.instance.displayCarousel.post(\n  displayCarouselRequest: DisplayCarouselRequestModel(\n    images: [img1, img2],\n    intervalMs: 3000,\n    transition: TefIPCarouselTransition.fade,\n    backgroundColor: '#000000',\n  ),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nasync function fileToBase64(file) {\n  return new Promise((resolve) => {\n    const reader = new FileReader();\n    reader.onload = () => resolve(reader.result.split(',')[1]);\n    reader.readAsDataURL(file);\n  });\n}\n\nconst img1 = await fileToBase64(imagemFile1);\nconst img2 = await fileToBase64(imagemFile2);\n\nconst res = await fetch('http://localhost:9050/display/carousel', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    images: [img1, img2],\n    intervalMs: 3000,\n    transition: 'fade',\n    backgroundColor: '#000000',\n  }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$img1 = base64_encode(file_get_contents('imagem1.png'));\n$img2 = base64_encode(file_get_contents('imagem2.png'));\n\n$ch = curl_init('http://localhost:9050/display/carousel');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'images'          => [$img1, $img2],\n    'intervalMs'      => 3000,\n    'transition'      => 'fade',\n    'backgroundColor' => '#000000',\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\nrequire 'base64'\n\nimg1 = Base64.strict_encode64(File.binread('imagem1.png'))\nimg2 = Base64.strict_encode64(File.binread('imagem2.png'))\n\nuri = URI('http://localhost:9050/display/carousel')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = {\n  images: [img1, img2],\n  intervalMs: 3000,\n  transition: 'fade',\n  backgroundColor: '#000000',\n}.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/display/#post-displayclear","title":"POST /display/clear","text":"

    Remove qualquer conte\u00fado exibido na tela do terminal e retorna ao estado padr\u00e3o.

    N\u00e3o h\u00e1 corpo na requisi\u00e7\u00e3o.

    Resposta \u2014 200

    { \"message\": \"Display limpo com sucesso\" }\n
    "},{"location":"api/display/#exemplos-de-integracao_3","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/display/clear\n
    await TefIP.instance.displayClear.post();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/display/clear', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/display/clear');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/display/clear')\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/display/#post-displaypop","title":"POST /display/pop","text":"

    Fecha a sobreposi\u00e7\u00e3o atualmente exibida na tela, voltando \u00e0 tela anterior sem limpar o estado completo.

    N\u00e3o h\u00e1 corpo na requisi\u00e7\u00e3o.

    Resposta \u2014 200

    { \"message\": \"Display fechado com sucesso\" }\n
    "},{"location":"api/display/#exemplos-de-integracao_4","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/display/pop\n
    await TefIP.instance.displayPop.post();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/display/pop', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/display/pop');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/display/pop')\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/erros/","title":"C\u00f3digos de Erro","text":"

    O TEF IP utiliza c\u00f3digos de status HTTP padr\u00e3o para indicar o sucesso ou falha de uma requisi\u00e7\u00e3o. Todas as respostas de erro acompanham um corpo JSON com detalhes adicionais.

    "},{"location":"api/erros/#formato-de-erro","title":"Formato de Erro","text":"
    {\n  \"code\": 400,\n  \"message\": \"Mensagem descritiva do erro\"\n}\n
    "},{"location":"api/erros/#tabela-de-referencia","title":"Tabela de Refer\u00eancia","text":"C\u00f3digo Nome Significado para o Integrador 200 OK A opera\u00e7\u00e3o foi processada com sucesso. 204 No Content Sucesso, mas n\u00e3o h\u00e1 conte\u00fado de retorno (ex.: respostas de CORS). 400 Bad Request O corpo da requisi\u00e7\u00e3o (JSON/XML/Bin\u00e1rio) \u00e9 inv\u00e1lido ou faltam campos obrigat\u00f3rios. 401 Unauthorized As credenciais de Basic Auth est\u00e3o ausentes ou incorretas. 403 Forbidden A opera\u00e7\u00e3o foi recusada pela adquirente ou as permiss\u00f5es s\u00e3o insuficientes (ex.: /restart em plataforma n\u00e3o-m\u00f3vel). 404 Not Found Recurso inexistente: venda, item, pagamento, desconto ou acr\u00e9scimo n\u00e3o encontrado, ou nenhuma pergunta ativa em /ask/cancel. 409 Conflict Voc\u00ea tentou iniciar uma opera\u00e7\u00e3o que conflita com o estado atual (ex.: iniciar venda com outra aberta). 499 Cancelled Pergunta/formul\u00e1rio (/ask, /ask/form) cancelado pelo usu\u00e1rio ou via /ask/cancel. 500 Internal Error Ocorreu um erro inesperado no servidor. Verifique os logs do dispositivo. 503 Service Unavailable O servidor est\u00e1 ocupado (isBusy) ou o aplicativo est\u00e1 em segundo plano (isActive = false)."},{"location":"api/erros/#sugestoes-de-tratamento","title":"Sugest\u00f5es de Tratamento","text":""},{"location":"api/logs/","title":"Logs","text":"

    Endpoints para consultar, acompanhar em tempo real e exportar os logs do TEF IP. Eles ajudam a investigar falhas de integra\u00e7\u00e3o, comportamento do servidor e eventos de roteamento HTTP.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    Quando usar cada endpoint

    Use GET /logs para an\u00e1lise pontual, GET /logs/stream para monitoramento em tempo real e GET /logs/zip/download quando precisar anexar os registros a um chamado ou auditoria.

    "},{"location":"api/logs/#get-logs","title":"GET /logs","text":"

    Retorna uma lista de logs, com suporte a filtros por n\u00edvel, origem, intervalo de datas e texto.

    Query parameters

    Par\u00e2metro Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o level string N\u00e3o N\u00edvel do log: fatal, error, warning, info, trace, path, debug source string N\u00e3o Origem do log: app, router, http dateFrom string N\u00e3o Data/hora inicial em ISO 8601 dateTo string N\u00e3o Data/hora final em ISO 8601 limit int N\u00e3o N\u00famero m\u00e1ximo de registros retornados search string N\u00e3o Busca parcial em message e details

    Resposta

    [\n  {\n    \"id\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n    \"level\": \"error\",\n    \"source\": \"http\",\n    \"message\": \"POST /transaction retornou 500\",\n    \"details\": \"Exception: connection refused\\n  at ...\",\n    \"createdAt\": \"2024-06-15T14:30:00.000Z\"\n  }\n]\n
    Campo Tipo Descri\u00e7\u00e3o id string Identificador \u00fanico do log level string Severidade do evento source string Origem do log message string Mensagem principal details string | null Detalhes adicionais, como stack trace ou payload createdAt string Data/hora em ISO 8601"},{"location":"api/logs/#exemplos-de-integracao","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     \"http://localhost:9050/logs?level=error&source=http&limit=50&search=timeout\"\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal logs = await TefIP.instance.log.getAll(\n  level: TefIPLogLevel.error,\n  source: TefIPLogSource.http,\n  limit: 50,\n  search: 'timeout',\n);\nprint(logs.first.message);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/logs?level=error&source=http&limit=50&search=timeout', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/logs?level=error&source=http&limit=50&search=timeout');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/logs?level=error&source=http&limit=50&search=timeout')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/logs/#get-logszipdownload","title":"GET /logs/zip/download","text":"

    Exporta os logs filtrados como um arquivo ZIP. O arquivo retornado cont\u00e9m tefip_logs.log em texto plano.

    Query parameters

    Os mesmos filtros de GET /logs s\u00e3o aceitos, exceto search.

    Resposta \u2014 200

    Header Valor Content-Type application/zip Content-Disposition attachment; filename=\"tefip_logs.zip\""},{"location":"api/logs/#exemplos-de-integracao_1","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -o tefip_logs.zip \\\n     \"http://localhost:9050/logs/zip/download?level=error&limit=200\"\n
    import 'dart:io';\n\nfinal zipBytes = await TefIP.instance.log.downloadZip(\n  level: TefIPLogLevel.error,\n  limit: 200,\n);\nawait File('tefip_logs.zip').writeAsBytes(zipBytes);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/logs/zip/download?level=error&limit=200', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst blob = await res.blob();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/logs/zip/download?level=error&limit=200');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$zipBytes = curl_exec($ch);\ncurl_close($ch);\nfile_put_contents('tefip_logs.zip', $zipBytes);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\n\nuri = URI('http://localhost:9050/logs/zip/download?level=error&limit=200')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\nFile.binwrite('tefip_logs.zip', res.body)\n
    "},{"location":"api/logs/#get-logsstream","title":"GET /logs/stream","text":"

    Abre uma conex\u00e3o SSE (Server-Sent Events) e envia um novo evento para cada log gerado enquanto a conex\u00e3o estiver aberta.

    Resposta

    data: {\"id\":\"abc\",\"level\":\"info\",\"source\":\"http\",\"message\":\"POST /transaction 200\",\"details\":null,\"createdAt\":\"2024-06-15T14:30:00.000Z\"}\n
    Header Valor Content-Type text/event-stream Cache-Control no-cache X-Accel-Buffering no"},{"location":"api/logs/#exemplos-de-integracao_2","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -N -u admin:1234 \\\n     http://localhost:9050/logs/stream\n
    TefIP.instance.log.stream().listen((log) {\n  print('[${log.level.name}] ${log.message}');\n});\n
    // TODO: EventSource n\u00e3o permite definir Authorization; para browser, prefira um proxy autenticado\nconst res = await fetch('http://localhost:9050/logs/stream', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\n\nconst reader = res.body.getReader();\nconst decoder = new TextDecoder();\n\nwhile (true) {\n  const { done, value } = await reader.read();\n  if (done) break;\n  console.log(decoder.decode(value, { stream: true }));\n}\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/logs/stream');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($curl, $chunk) {\n    echo $chunk;\n    return strlen($chunk);\n});\ncurl_exec($ch);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\n\nuri = URI('http://localhost:9050/logs/stream')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\n\nNet::HTTP.start(uri.hostname, uri.port) do |http|\n  http.request(req) do |res|\n    res.read_body do |chunk|\n      puts chunk\n    end\n  end\nend\n
    "},{"location":"api/notification/","title":"Notifica\u00e7\u00f5es","text":"

    Endpoint para disparar uma notifica\u00e7\u00e3o local no dispositivo que executa o TEF IP. \u00c9 \u00fatil para chamar o operador de volta ao app ou sinalizar um evento importante no fluxo de pagamento.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    Comportamento no Android

    Em dispositivos Android, o TEF IP acorda a tela antes de exibir a notifica\u00e7\u00e3o.

    "},{"location":"api/notification/#post-notification","title":"POST /notification","text":"

    Envia uma notifica\u00e7\u00e3o local com t\u00edtulo e mensagem.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"title\": \"Novo pagamento\",\n  \"message\": \"Restaure o aplicativo para processar\"\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o title string Sim T\u00edtulo da notifica\u00e7\u00e3o message string Sim Corpo da notifica\u00e7\u00e3o

    Resposta \u2014 200

    {\n  \"message\": \"Notifica\u00e7\u00e3o enviada com sucesso\"\n}\n

    Resposta \u2014 400

    {\n  \"code\": 400,\n  \"message\": \"Corpo da requisi\u00e7\u00e3o inv\u00e1lido\"\n}\n
    "},{"location":"api/notification/#exemplos-de-integracao","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/notification \\\n     -d '{\"title\":\"Novo pagamento\",\"message\":\"Restaure o aplicativo para processar\"}'\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nawait TefIP.instance.notification.post(\n  request: NotificationRequestModel(\n    title: 'Novo pagamento',\n    message: 'Restaure o aplicativo para processar',\n  ),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/notification', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    title: 'Novo pagamento',\n    message: 'Restaure o aplicativo para processar',\n  }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/notification');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'title' => 'Novo pagamento',\n    'message' => 'Restaure o aplicativo para processar',\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/notification')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = {\n  title: 'Novo pagamento',\n  message: 'Restaure o aplicativo para processar',\n}.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/print/","title":"Impress\u00e3o","text":"

    Endpoints para imprimir imagens, comprovantes formatados e cupons fiscais (XML/DANFE) na impressora do terminal.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    Bloqueio durante impress\u00e3o

    Todos os endpoints de impress\u00e3o definem isBusy = true enquanto a opera\u00e7\u00e3o est\u00e1 em andamento. Novas requisi\u00e7\u00f5es que verificam o estado ocupado ser\u00e3o rejeitadas com 503.

    "},{"location":"api/print/#impressao-fiscal-danfexml","title":"Impress\u00e3o Fiscal (DANFE/XML)","text":"

    O TEF IP inclui um parser avan\u00e7ado para documentos fiscais eletr\u00f4nicos. Ao inv\u00e9s de o seu sistema formatar o comprovante manualmente, voc\u00ea pode enviar o XML original da nota e o terminal cuidar\u00e1 da renderiza\u00e7\u00e3o.

    "},{"location":"api/print/#funcionamento-do-parser","title":"Funcionamento do Parser","text":"

    O servidor processa o XML e mapeia campos como: * Dados do Emitente: Nome, CNPJ, Inscri\u00e7\u00e3o Estadual, Endere\u00e7o. * Dados do Destinat\u00e1rio: Nome/Raz\u00e3o Social, CPF/CNPJ. * Itens: Descri\u00e7\u00e3o, quantidade, valor unit\u00e1rio e total. * Totais: BC ICMS, Valor ICMS, Valor Total da Nota. * Informa\u00e7\u00f5es de Pagamento: Formas de pagamento utilizadas. * Protocolo de Autoriza\u00e7\u00e3o: N\u00famero, data e hora da autoriza\u00e7\u00e3o.

    "},{"location":"api/print/#requisitos-do-xml","title":"Requisitos do XML","text":"

    Para que a impress\u00e3o ocorra sem erros, o XML deve: 1. Seguir o padr\u00e3o nacional de NF-e/NFC-e (vers\u00e3o 4.00). 2. Estar completo e conter as tags de protocolo de autoriza\u00e7\u00e3o (<protNFe> ou <protCTe>). 3. Ser enviado com o header Content-Type: text/xml.

    Customiza\u00e7\u00e3o

    Se precisar de um layout muito espec\u00edfico ou marcas pr\u00f3prias que n\u00e3o constam no XML, utilize o endpoint POST /print/text para montar o comprovante linha por linha.

    "},{"location":"api/print/#post-printimage","title":"POST /print/image","text":"

    Imprime uma imagem diretamente na impressora do terminal.

    Corpo da requisi\u00e7\u00e3o

    Bytes bin\u00e1rios da imagem, enviados diretamente no corpo da requisi\u00e7\u00e3o.

    Header Valor Content-Type application/octet-stream

    Resposta \u2014 200

    { \"message\": \"Impress\u00e3o realizada com sucesso\" }\n

    Resposta \u2014 400 (nenhuma imagem enviada)

    { \"code\": 400, \"message\": \"Nenhuma imagem enviada\" }\n

    Resposta \u2014 500 (erro na impress\u00e3o)

    { \"code\": 500, \"message\": \"Erro ao imprimir\" }\n
    "},{"location":"api/print/#exemplos-de-integracao","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/octet-stream\" \\\n     -X POST http://localhost:9050/print/image \\\n     --data-binary @comprovante.png\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nimport 'dart:io';\n\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal imageData = await File('comprovante.png').readAsBytes();\nawait TefIP.instance.printImage.post(imageData: imageData);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst imageBytes = await fetch('/comprovante.png').then(r => r.arrayBuffer());\nconst res = await fetch('http://localhost:9050/print/image', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/octet-stream',\n  },\n  body: imageBytes,\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$imageData = file_get_contents('comprovante.png');\n$ch = curl_init('http://localhost:9050/print/image');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/octet-stream']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, $imageData);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nimage_data = File.binread('comprovante.png')\nuri = URI('http://localhost:9050/print/image')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/octet-stream')\nreq.basic_auth('admin', '1234')\nreq.body = image_data\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/print/#post-printtext","title":"POST /print/text","text":"

    Imprime um comprovante com formata\u00e7\u00e3o personalizada. O corpo \u00e9 um array JSON de instru\u00e7\u00f5es de impress\u00e3o.

    Corpo da requisi\u00e7\u00e3o

    [\n  { \"text\": { \"value\": \"COMPROVANTE\", \"size\": 20, \"bold\": true,  \"align\": \"center\" } },\n  { \"line\": { \"divider\": true } },\n  { \"text\": { \"value\": \"Produto: Coca-Cola\",  \"size\": 14, \"bold\": false, \"align\": \"left\" } },\n  { \"text\": { \"value\": \"Valor:   R$ 5,00\",    \"size\": 14, \"bold\": false, \"align\": \"left\" } },\n  { \"line\": { \"divider\": true } },\n  { \"text\": { \"value\": \"Obrigado pela compra!\", \"size\": 14, \"bold\": false, \"align\": \"center\" } }\n]\n

    Cada item do array define um elemento de impress\u00e3o pela sua chave de tipo:

    Tipo Exemplo Texto { \"text\": { \"value\": \"...\", \"size\": 16, \"bold\": false, \"align\": \"left\" } } Divisor { \"line\": { \"divider\": true } }

    Resposta \u2014 200

    { \"message\": \"Impress\u00e3o realizada com sucesso\" }\n

    Resposta \u2014 400 (nenhum conte\u00fado enviado)

    { \"code\": 500, \"message\": \"Nenhum texto enviado\" }\n
    "},{"location":"api/print/#exemplos-de-integracao_1","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/print/text \\\n     -d '[\n       {\"text\": {\"value\": \"COMPROVANTE\", \"size\": 20, \"bold\": true, \"align\": \"center\"}},\n       {\"line\": {\"divider\": true}},\n       {\"text\": {\"value\": \"Obrigado!\", \"size\": 14, \"bold\": false, \"align\": \"center\"}}\n     ]'\n
    await TefIP.instance.printText.post(\n  text: [\n    {'text': {'value': 'COMPROVANTE', 'size': 20, 'bold': true,  'align': 'center'}},\n    {'line': {'divider': true}},\n    {'text': {'value': 'Obrigado!',   'size': 14, 'bold': false, 'align': 'center'}},\n  ],\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/print/text', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify([\n    { text: { value: 'COMPROVANTE', size: 20, bold: true,  align: 'center' } },\n    { line: { divider: true } },\n    { text: { value: 'Obrigado!',   size: 14, bold: false, align: 'center' } },\n  ]),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/print/text');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    ['text' => ['value' => 'COMPROVANTE', 'size' => 20, 'bold' => true,  'align' => 'center']],\n    ['line' => ['divider' => true]],\n    ['text' => ['value' => 'Obrigado!',   'size' => 14, 'bold' => false, 'align' => 'center']],\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/print/text')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = [\n  { text: { value: 'COMPROVANTE', size: 20, bold: true,  align: 'center' } },\n  { line: { divider: true } },\n  { text: { value: 'Obrigado!',   size: 14, bold: false, align: 'center' } },\n].to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/print/#post-printxml","title":"POST /print/xml","text":"

    Imprime um cupom fiscal a partir de um XML de NF-e/DANFE. O TEF IP faz o parse do XML e renderiza automaticamente o layout do cupom fiscal.

    Corpo da requisi\u00e7\u00e3o

    String com o conte\u00fado do XML da NF-e.

    Header Valor Content-Type text/xml
    <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<nfeProc xmlns=\"http://www.portalfiscal.inf.br/nfe\" versao=\"4.00\">\n  ...\n</nfeProc>\n

    Resposta \u2014 200

    { \"message\": \"Impress\u00e3o realizada com sucesso\" }\n

    Resposta \u2014 400 (nenhum XML enviado)

    { \"code\": 403, \"message\": \"Nenhum XML enviado\" }\n

    Resposta \u2014 500 (erro na impress\u00e3o)

    { \"code\": 500, \"message\": \"Erro ao imprimir\" }\n
    "},{"location":"api/print/#exemplos-de-integracao_2","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: text/xml\" \\\n     -X POST http://localhost:9050/print/xml \\\n     --data-binary @nota-fiscal.xml\n
    import 'dart:io';\n\nfinal xml = await File('nota-fiscal.xml').readAsString();\nawait TefIP.instance.printXml.post(xml: xml);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst xml = await fetch('/nota-fiscal.xml').then(r => r.text());\nconst res = await fetch('http://localhost:9050/print/xml', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'text/xml',\n  },\n  body: xml,\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$xml = file_get_contents('nota-fiscal.xml');\n$ch = curl_init('http://localhost:9050/print/xml');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: text/xml']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, $xml);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nxml = File.read('nota-fiscal.xml')\nuri = URI('http://localhost:9050/print/xml')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'text/xml')\nreq.basic_auth('admin', '1234')\nreq.body = xml\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/print/#post-printacbr","title":"POST /print/acbr","text":"

    Imprime um layout descrito no formato de tags ACBr \u2014 texto puro enviado diretamente no corpo da requisi\u00e7\u00e3o (sem JSON). \u00datil para reaproveitar layouts de PDV j\u00e1 escritos nesse padr\u00e3o.

    Corpo da requisi\u00e7\u00e3o

    Texto puro com as tags ACBr.

    Header Valor Content-Type text/plain

    Tags suportadas

    Categoria Tags Estilo <n> negrito \u00b7 <i> it\u00e1lico \u00b7 <s> sublinhado \u00b7 <in> invertido \u00b7 <e> expandido \u00b7 <c> condensado \u00b7 <a> altura dupla Alinhamento </ce> centro \u00b7 </ae> esquerda \u00b7 </ad> direita Estrutura </zera> reset \u00b7 </fn> fonte normal \u00b7 </linha_simples> e </linha_dupla> divis\u00f3rias \u00b7 <qrcode>...</qrcode> QR Code

    Tags ignoradas

    </corte_total>, </corte> e </logo> s\u00e3o aceitas, mas n\u00e3o produzem efeito no terminal.

    Resposta \u2014 200

    { \"message\": \"Impress\u00e3o realizada com sucesso\" }\n

    Resposta \u2014 400 (nenhum conte\u00fado enviado)

    { \"code\": 400, \"message\": \"Nenhum conte\u00fado enviado\" }\n

    Resposta \u2014 500 (erro na impress\u00e3o)

    { \"code\": 500, \"message\": \"Erro ao imprimir\" }\n
    "},{"location":"api/print/#exemplos-de-integracao_3","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: text/plain\" \\\n     -X POST http://localhost:9050/print/acbr \\\n     --data-binary $'</ce><n>TEF IP</n>\\n</ae>Obrigado pela compra!\\n</linha_simples>'\n
    // TODO: o SDK Dart ainda n\u00e3o exp\u00f5e m\u00e9todo para ACBr \u2014 usando http diretamente\nimport 'package:http/http.dart' as http;\n\nfinal layout = '</ce><n>TEF IP</n>\\n</ae>Obrigado pela compra!\\n</linha_simples>';\nawait http.post(\n  Uri.parse('http://localhost:9050/print/acbr'),\n  headers: {\n    'Authorization': 'Basic ${base64Encode(utf8.encode('admin:1234'))}',\n    'Content-Type': 'text/plain',\n  },\n  body: layout,\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst layout = '</ce><n>TEF IP</n>\\n</ae>Obrigado pela compra!\\n</linha_simples>';\nconst res = await fetch('http://localhost:9050/print/acbr', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'text/plain',\n  },\n  body: layout,\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$layout = \"</ce><n>TEF IP</n>\\n</ae>Obrigado pela compra!\\n</linha_simples>\";\n$ch = curl_init('http://localhost:9050/print/acbr');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: text/plain']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, $layout);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nlayout = \"</ce><n>TEF IP</n>\\n</ae>Obrigado pela compra!\\n</linha_simples>\"\nuri = URI('http://localhost:9050/print/acbr')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'text/plain')\nreq.basic_auth('admin', '1234')\nreq.body = layout\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/","title":"Venda","text":"

    Endpoints para gerenciar vendas: abrir um carrinho, adicionar itens e pagamentos, e finalizar ou cancelar a venda. A venda organiza o que foi vendido \u2014 o pagamento financeiro \u00e9 feito separadamente via POST /transaction.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    Fluxo de venda

    Uma venda segue a sequ\u00eancia: iniciar \u2192 adicionar itens \u2192 adicionar pagamentos \u2192 finalizar (ou cancelar). Apenas uma venda pode estar ativa por vez.

    "},{"location":"api/sale/#ciclo-de-vida-da-venda","title":"Ciclo de Vida da Venda","text":"

    Diferente de uma transa\u00e7\u00e3o avulsa, uma Venda no TEF IP \u00e9 uma sess\u00e3o que acumula itens e pagamentos antes de ser consolidada. O servidor gerencia o estado dessa venda internamente.

    "},{"location":"api/sale/#fluxo-de-estados","title":"Fluxo de Estados","text":"
    stateDiagram-v2\n    [*] --> Aberta: POST /sale\n    Aberta --> Aberta: itens (POST/PATCH/DELETE /sale/item \u00b7 cancel \u00b7 clear)\n    Aberta --> Aberta: pagamentos (POST/PATCH/DELETE /sale/payment \u00b7 clear)\n    Aberta --> Aberta: descontos (POST/PATCH/DELETE /sale/discount \u00b7 clear)\n    Aberta --> Aberta: acr\u00e9scimos (POST/PATCH/DELETE /sale/addition \u00b7 clear)\n    Aberta --> Finalizada: POST /sale/finalize\n    Aberta --> Cancelada: POST /sale/cancel\n    Finalizada --> [*]\n    Cancelada --> [*]
    "},{"location":"api/sale/#regras-importantes","title":"Regras Importantes","text":"
    1. Exclusividade: Apenas uma venda pode estar ativa por vez no dispositivo. Tentar iniciar uma nova sem encerrar a anterior resulta em erro 409 Conflict.
    2. Sincroniza\u00e7\u00e3o: Opera\u00e7\u00f5es de venda s\u00e3o s\u00edncronas. O servidor retorna a confirma\u00e7\u00e3o assim que o estado interno \u00e9 atualizado.
    3. Documento Fiscal: Os itens e pagamentos adicionados servem de base para a montagem de cupons fiscais e DANFE.
    4. Pagamento financeiro: A venda registra o qu\u00ea foi vendido e como foi pago \u2014 mas n\u00e3o processa o d\u00e9bito financeiro. O pagamento no cart\u00e3o ou PIX \u00e9 feito separadamente via POST /transaction. Finalize a venda ap\u00f3s confirmar a aprova\u00e7\u00e3o da transa\u00e7\u00e3o.
    5. Limpeza: Ao finalizar ou cancelar, o TEF IP limpa automaticamente qualquer conte\u00fado que esteja sendo exibido no visor do terminal (pop de displays).
    "},{"location":"api/sale/#forma-das-respostas","title":"Forma das respostas","text":"

    As rotas de venda seguem uma conven\u00e7\u00e3o consistente:

    O cupom completo (SaleCoupon) tem o seguinte formato:

    {\n  \"sale\": {\n    \"customerDocument\": \"123.456.789-00\",\n    \"customerName\": \"Jo\u00e3o Silva\",\n    \"sellerName\": \"Maria\",\n    \"additionalInfo\": \"Balc\u00e3o 3\",\n    \"total\": null\n  },\n  \"items\": [],\n  \"payments\": [],\n  \"discounts\": [],\n  \"additions\": [],\n  \"summary\": {\n    \"subtotal\": 0,\n    \"surcharge\": 0,\n    \"discount\": 0,\n    \"itemDiscount\": 0,\n    \"itemAddition\": 0,\n    \"total\": 0\n  }\n}\n

    Valores monet\u00e1rios em reais

    Todos os valores (unitPrice, total, value, discount, addition, etc.) trafegam em reais decimais (ex.: 10.50), n\u00e3o em centavos. Descontos e acr\u00e9scimos s\u00e3o armazenados em m\u00f3dulo (valor absoluto): enviar -5.00 \u00e9 equivalente a 5.00.

    "},{"location":"api/sale/#get-sale","title":"GET /sale","text":"

    Retorna o estado da venda ativa (o cupom completo). \u00datil para sincronizar o carrinho a qualquer momento.

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    "},{"location":"api/sale/#exemplos-de-integracao","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     http://localhost:9050/sale\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal coupon = await TefIP.instance.sale.get();\nprint('Total: ${coupon.summary.total}');\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale', {\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#post-sale","title":"POST /sale","text":"

    Inicia uma nova venda. Retorna 409 se j\u00e1 existir uma venda ativa.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"customerDocument\": \"123.456.789-00\",\n  \"customerName\": \"Jo\u00e3o Silva\",\n  \"sellerName\": \"Maria\",\n  \"additionalInfo\": \"Balc\u00e3o 3\"\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o customerDocument string N\u00e3o CPF ou CNPJ do cliente customerName string N\u00e3o Nome do cliente exibido no terminal sellerName string N\u00e3o Nome do vendedor exibido no terminal additionalInfo string N\u00e3o Informa\u00e7\u00e3o adicional exibida no terminal total number N\u00e3o Valor total a exibir na tela de venda

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    Resposta \u2014 409 (j\u00e1 existe uma venda ativa)

    { \"code\": 409, \"message\": \"J\u00e1 existe uma venda ativa!\" }\n
    "},{"location":"api/sale/#exemplos-de-integracao_1","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/sale \\\n     -d '{\"customerName\":\"Jo\u00e3o Silva\",\"sellerName\":\"Maria\"}'\n
    final coupon = await TefIP.instance.sale.post(\n  request: SaleStartRequestModel(\n    customerName: 'Jo\u00e3o Silva',\n    sellerName: 'Maria',\n  ),\n);\nprint('Itens: ${coupon.items.length}');\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ customerName: 'Jo\u00e3o Silva', sellerName: 'Maria' }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'customerName' => 'Jo\u00e3o Silva',\n    'sellerName'   => 'Maria',\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { customerName: 'Jo\u00e3o Silva', sellerName: 'Maria' }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#patch-sale","title":"PATCH /sale","text":"

    Atualiza os dados da venda ativa (cliente, vendedor, informa\u00e7\u00f5es adicionais). Usa o mesmo corpo que POST /sale.

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    "},{"location":"api/sale/#exemplos-de-integracao_2","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X PATCH http://localhost:9050/sale \\\n     -d '{\"customerName\":\"Maria Souza\"}'\n
    await TefIP.instance.sale.patch(\n  request: SaleStartRequestModel(customerName: 'Maria Souza'),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale', {\n  method: 'PATCH',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ customerName: 'Maria Souza' }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['customerName' => 'Maria Souza']));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale')\nreq = Net::HTTP::Patch.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { customerName: 'Maria Souza' }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#delete-saleclear","title":"DELETE /sale/clear","text":"

    Esvazia a venda ativa por completo \u2014 remove todos os itens, pagamentos, descontos e acr\u00e9scimos, preservando o cabe\u00e7alho (cliente/vendedor).

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon) j\u00e1 esvaziado (ver Forma das respostas).

    "},{"location":"api/sale/#exemplos-de-integracao_3","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X DELETE http://localhost:9050/sale/clear\n
    await TefIP.instance.sale.clear();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/clear', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/clear');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/clear')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#post-saleitem","title":"POST /sale/item","text":"

    Adiciona um item ao carrinho da venda ativa.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"id\": \"item-001\",\n  \"code\": \"7891234567890\",\n  \"description\": \"Coca-Cola 350ml\",\n  \"canceled\": false,\n  \"quantity\": 2.0,\n  \"unitPrice\": 5.00,\n  \"discount\": 0.50,\n  \"addition\": null,\n  \"total\": 9.50,\n  \"additionalInfo\": null\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o id string Sim Identificador \u00fanico do item code string Sim C\u00f3digo do produto (ex.: EAN/c\u00f3digo de barras) description string Sim Descri\u00e7\u00e3o exibida no terminal canceled bool N\u00e3o Item marcado como cancelado (padr\u00e3o: false) quantity number Sim Quantidade unitPrice number Sim Pre\u00e7o unit\u00e1rio (reais) discount number N\u00e3o Desconto aplicado ao item (m\u00f3dulo) addition number N\u00e3o Acr\u00e9scimo aplicado ao item total number Sim Valor total do item (reais) additionalInfo string N\u00e3o Informa\u00e7\u00e3o adicional

    Resposta \u2014 200

    Retorna o item criado (mesmo formato do corpo da requisi\u00e7\u00e3o).

    {\n  \"id\": \"item-001\",\n  \"code\": \"7891234567890\",\n  \"description\": \"Coca-Cola 350ml\",\n  \"canceled\": false,\n  \"quantity\": 2.0,\n  \"unitPrice\": 5.00,\n  \"discount\": 0.50,\n  \"addition\": null,\n  \"total\": 9.50,\n  \"additionalInfo\": null\n}\n

    Resposta \u2014 400 (item duplicado)

    { \"code\": 400, \"message\": \"Item j\u00e1 existente na venda!\" }\n
    "},{"location":"api/sale/#exemplos-de-integracao_4","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/sale/item \\\n     -d '{\"id\":\"item-001\",\"code\":\"7891234567890\",\"description\":\"Coca-Cola 350ml\",\"quantity\":2,\"unitPrice\":5.00,\"total\":9.50}'\n
    final item = await TefIP.instance.saleItem.post(\n  item: SaleItemModel(\n    id: 'item-001',\n    code: '7891234567890',\n    description: 'Coca-Cola 350ml',\n    quantity: 2,\n    unitPrice: 5.00,\n    total: 9.50,\n  ),\n);\nprint(item.id);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/item', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    id: 'item-001',\n    code: '7891234567890',\n    description: 'Coca-Cola 350ml',\n    quantity: 2,\n    unitPrice: 5.00,\n    total: 9.50,\n  }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/item');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'id'          => 'item-001',\n    'code'        => '7891234567890',\n    'description' => 'Coca-Cola 350ml',\n    'quantity'    => 2,\n    'unitPrice'   => 5.00,\n    'total'       => 9.50,\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/item')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = {\n  id: 'item-001', code: '7891234567890', description: 'Coca-Cola 350ml',\n  quantity: 2, unitPrice: 5.00, total: 9.50,\n}.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#patch-saleitemitemid","title":"PATCH /sale/item/{itemId}","text":"

    Atualiza os dados de um item j\u00e1 adicionado \u00e0 venda. O id no corpo \u00e9 ignorado \u2014 o identificador vem do par\u00e2metro de rota.

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o itemId string Identificador do item a atualizar

    Corpo igual ao de POST /sale/item. O id no corpo \u00e9 ignorado \u2014 o identificador vem do par\u00e2metro de rota.

    Resposta \u2014 200

    Retorna o item atualizado (mesmo formato do corpo da requisi\u00e7\u00e3o).

    "},{"location":"api/sale/#exemplos-de-integracao_5","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X PATCH http://localhost:9050/sale/item/item-001 \\\n     -d '{\"code\":\"7891234567890\",\"description\":\"Coca-Cola 350ml\",\"quantity\":3,\"unitPrice\":5.00,\"total\":14.50}'\n
    await TefIP.instance.saleItem.patch(\n  itemId: 'item-001',\n  item: SaleItemModel(\n    code: '7891234567890',\n    description: 'Coca-Cola 350ml',\n    quantity: 3,\n    unitPrice: 5.00,\n    total: 14.50,\n  ),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/item/item-001', {\n  method: 'PATCH',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ code: '7891234567890', description: 'Coca-Cola 350ml', quantity: 3, unitPrice: 5.00, total: 14.50 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/item/item-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'code' => '7891234567890', 'description' => 'Coca-Cola 350ml',\n    'quantity' => 3, 'unitPrice' => 5.00, 'total' => 14.50,\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/item/item-001')\nreq = Net::HTTP::Patch.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { code: '7891234567890', description: 'Coca-Cola 350ml', quantity: 3, unitPrice: 5.00, total: 14.50 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#delete-saleitemclear","title":"DELETE /sale/item/clear","text":"

    Remove todos os itens da venda ativa, preservando pagamentos, descontos e acr\u00e9scimos.

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    "},{"location":"api/sale/#exemplos-de-integracao_6","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X DELETE http://localhost:9050/sale/item/clear\n
    await TefIP.instance.saleItem.clear();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/item/clear', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/item/clear');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/item/clear')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#delete-saleitemitemid","title":"DELETE /sale/item/{itemId}","text":"

    Remove um item permanentemente do carrinho da venda ativa.

    Cancel vs Delete

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o itemId string Identificador do item a remover

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    "},{"location":"api/sale/#exemplos-de-integracao_7","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X DELETE http://localhost:9050/sale/item/item-001\n
    await TefIP.instance.saleItem.delete(itemId: 'item-001');\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/item/item-001', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/item/item-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/item/item-001')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#post-saleitemitemidcancel","title":"POST /sale/item/{itemId}/cancel","text":"

    Marca um item como cancelado sem remov\u00ea-lo do carrinho. \u00datil para manter o hist\u00f3rico da venda.

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o itemId string Identificador do item a cancelar

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon) com o item marcado como canceled: true (ver Forma das respostas).

    "},{"location":"api/sale/#exemplos-de-integracao_8","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/sale/item/item-001/cancel\n
    await TefIP.instance.saleItem.cancel(itemId: 'item-001');\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/item/item-001/cancel', {\n  method: 'POST',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/item/item-001/cancel');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/item/item-001/cancel')\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#post-salepayment","title":"POST /sale/payment","text":"

    Adiciona uma forma de pagamento \u00e0 venda ativa.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"id\": \"pgto-001\",\n  \"tPag\": \"17\",\n  \"description\": null,\n  \"value\": 50.00,\n  \"additionalInfo\": null\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o id string Sim Identificador \u00fanico do pagamento tPag string N\u00e3o C\u00f3digo do tipo de pagamento (ver tabela abaixo; padr\u00e3o \"99\") description string N\u00e3o Descri\u00e7\u00e3o exibida no terminal value number Sim Valor do pagamento (reais) additionalInfo string N\u00e3o Informa\u00e7\u00e3o adicional

    Valores de tPag (c\u00f3digo num\u00e9rico \u2014 o mesmo c\u00f3digo da adquirente)

    C\u00f3digo (tPag) Enum SDK Descri\u00e7\u00e3o \"01\" money Dinheiro \"03\" credit Cr\u00e9dito \"04\" debit D\u00e9bito \"05\" gift Cart\u00e3o-presente \"17\" pix \u00b7 veroWallet PIX / Carteira digital Vero \"99\" unknown \u00b7 voucher \u00b7 adm \u00b7 cancel \u00b7 cancelDigitalWallet Demais tipos

    Envie o c\u00f3digo num\u00e9rico, n\u00e3o o nome

    No JSON cru, tPag deve ser o c\u00f3digo num\u00e9rico (\"17\"), n\u00e3o o nome (\"pix\"). Um nome n\u00e3o reconhecido \u00e9 interpretado como \"99\" (desconhecido). No SDK Dart, use o enum TefIPSalePaymentType.pix \u2014 ele converte para o c\u00f3digo automaticamente.

    Resposta \u2014 200

    Retorna o pagamento criado (mesmo formato do corpo, com tPag num\u00e9rico).

    {\n  \"id\": \"pgto-001\",\n  \"tPag\": \"17\",\n  \"description\": null,\n  \"value\": 50.00,\n  \"additionalInfo\": null\n}\n

    Resposta \u2014 400 (pagamento duplicado)

    { \"code\": 400, \"message\": \"Pagamento j\u00e1 existente na venda!\" }\n
    "},{"location":"api/sale/#exemplos-de-integracao_9","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/sale/payment \\\n     -d '{\"id\":\"pgto-001\",\"tPag\":\"17\",\"value\":50.00}'\n
    final payment = await TefIP.instance.salePayment.post(\n  payment: SalePaymentModel(\n    id: 'pgto-001',\n    type: TefIPSalePaymentType.pix,\n    value: 50.00,\n  ),\n);\nprint(payment.id);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/payment', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ id: 'pgto-001', tPag: '17', value: 50.00 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/payment');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['id' => 'pgto-001', 'tPag' => '17', 'value' => 50.00]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/payment')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { id: 'pgto-001', tPag: '17', value: 50.00 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#patch-salepaymentpaymentid","title":"PATCH /sale/payment/{paymentId}","text":"

    Atualiza os dados de um pagamento j\u00e1 adicionado \u00e0 venda.

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o paymentId string Identificador do pagamento a atualizar

    Corpo igual ao de POST /sale/payment. O id no corpo \u00e9 ignorado \u2014 vem do par\u00e2metro de rota.

    Resposta \u2014 200

    Retorna o pagamento atualizado (com tPag num\u00e9rico).

    "},{"location":"api/sale/#exemplos-de-integracao_10","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X PATCH http://localhost:9050/sale/payment/pgto-001 \\\n     -d '{\"tPag\":\"03\",\"value\":50.00}'\n
    await TefIP.instance.salePayment.patch(\n  paymentId: 'pgto-001',\n  payment: SalePaymentModel(\n    type: TefIPSalePaymentType.credit,\n    value: 50.00,\n  ),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/payment/pgto-001', {\n  method: 'PATCH',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ tPag: '03', value: 50.00 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/payment/pgto-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['tPag' => '03', 'value' => 50.00]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/payment/pgto-001')\nreq = Net::HTTP::Patch.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { tPag: '03', value: 50.00 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#delete-salepaymentclear","title":"DELETE /sale/payment/clear","text":"

    Remove todos os pagamentos da venda ativa, preservando itens, descontos e acr\u00e9scimos.

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    "},{"location":"api/sale/#exemplos-de-integracao_11","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X DELETE http://localhost:9050/sale/payment/clear\n
    await TefIP.instance.salePayment.clear();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/payment/clear', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/payment/clear');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/payment/clear')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#delete-salepaymentpaymentid","title":"DELETE /sale/payment/{paymentId}","text":"

    Remove uma forma de pagamento do carrinho da venda ativa.

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o paymentId string Identificador do pagamento a remover

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    "},{"location":"api/sale/#exemplos-de-integracao_12","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X DELETE http://localhost:9050/sale/payment/pgto-001\n
    await TefIP.instance.salePayment.delete(paymentId: 'pgto-001');\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/payment/pgto-001', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/payment/pgto-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/payment/pgto-001')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#descontos-da-venda","title":"Descontos da venda","text":"

    Descontos s\u00e3o valores subtra\u00eddos do total da venda, independentes dos descontos por item. Cada desconto tem um id pr\u00f3prio.

    "},{"location":"api/sale/#post-salediscount","title":"POST /sale/discount","text":"

    Adiciona um desconto \u00e0 venda ativa.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"id\": \"desc-001\",\n  \"description\": \"Cupom 10%\",\n  \"value\": 5.00,\n  \"additionalInfo\": null\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o id string Sim Identificador \u00fanico do desconto description string N\u00e3o Descri\u00e7\u00e3o exibida no terminal value number Sim Valor do desconto em reais (armazenado em m\u00f3dulo) additionalInfo string N\u00e3o Informa\u00e7\u00e3o adicional

    Resposta \u2014 200

    Retorna o desconto criado (mesmo formato do corpo).

    Resposta \u2014 400 (desconto duplicado)

    { \"code\": 400, \"message\": \"Desconto j\u00e1 existente na venda!\" }\n
    "},{"location":"api/sale/#exemplos-de-integracao_13","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/sale/discount \\\n     -d '{\"id\":\"desc-001\",\"description\":\"Cupom 10%\",\"value\":5.00}'\n
    final discount = await TefIP.instance.saleDiscount.post(\n  discount: SaleDiscountModel(id: 'desc-001', description: 'Cupom 10%', value: 5.00),\n);\nprint(discount.id);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/discount', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ id: 'desc-001', description: 'Cupom 10%', value: 5.00 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/discount');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'id' => 'desc-001', 'description' => 'Cupom 10%', 'value' => 5.00,\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/discount')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { id: 'desc-001', description: 'Cupom 10%', value: 5.00 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#patch-salediscountdiscountid","title":"PATCH /sale/discount/{discountId}","text":"

    Atualiza um desconto existente. O id no corpo \u00e9 ignorado \u2014 vem do par\u00e2metro de rota. Retorna o desconto atualizado.

    cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X PATCH http://localhost:9050/sale/discount/desc-001 \\\n     -d '{\"value\":7.50}'\n
    await TefIP.instance.saleDiscount.patch(\n  discountId: 'desc-001',\n  discount: SaleDiscountModel(id: 'desc-001', value: 7.50),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/discount/desc-001', {\n  method: 'PATCH',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ value: 7.50 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/discount/desc-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['value' => 7.50]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/discount/desc-001')\nreq = Net::HTTP::Patch.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { value: 7.50 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#delete-salediscountdiscountid-delete-salediscountclear","title":"DELETE /sale/discount/{discountId} \u00b7 DELETE /sale/discount/clear","text":"

    DELETE /sale/discount/{discountId} remove um desconto; DELETE /sale/discount/clear remove todos. Ambos retornam o cupom completo (SaleCoupon, ver Forma das respostas).

    cURLDartJavaScriptPHPRuby
    curl -u admin:1234 -X DELETE http://localhost:9050/sale/discount/desc-001\ncurl -u admin:1234 -X DELETE http://localhost:9050/sale/discount/clear\n
    await TefIP.instance.saleDiscount.delete(discountId: 'desc-001');\nawait TefIP.instance.saleDiscount.clear();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nawait fetch('http://localhost:9050/sale/discount/desc-001', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/discount/desc-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/discount/desc-001')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#acrescimos-da-venda","title":"Acr\u00e9scimos da venda","text":"

    Acr\u00e9scimos s\u00e3o valores somados ao total da venda (ex.: taxa de servi\u00e7o). Sim\u00e9tricos aos descontos, cada um com id pr\u00f3prio.

    "},{"location":"api/sale/#post-saleaddition","title":"POST /sale/addition","text":"

    Adiciona um acr\u00e9scimo \u00e0 venda ativa.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"id\": \"acrs-001\",\n  \"description\": \"Taxa de servi\u00e7o 10%\",\n  \"value\": 4.50,\n  \"additionalInfo\": null\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o id string Sim Identificador \u00fanico do acr\u00e9scimo description string N\u00e3o Descri\u00e7\u00e3o exibida no terminal value number Sim Valor do acr\u00e9scimo em reais (armazenado em m\u00f3dulo) additionalInfo string N\u00e3o Informa\u00e7\u00e3o adicional

    Resposta \u2014 200

    Retorna o acr\u00e9scimo criado (mesmo formato do corpo).

    Resposta \u2014 400 (acr\u00e9scimo duplicado)

    { \"code\": 400, \"message\": \"Acr\u00e9scimo j\u00e1 existente na venda!\" }\n
    "},{"location":"api/sale/#exemplos-de-integracao_14","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/sale/addition \\\n     -d '{\"id\":\"acrs-001\",\"description\":\"Taxa de servi\u00e7o 10%\",\"value\":4.50}'\n
    final addition = await TefIP.instance.saleAddition.post(\n  addition: SaleAdditionModel(id: 'acrs-001', description: 'Taxa de servi\u00e7o 10%', value: 4.50),\n);\nprint(addition.id);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/addition', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ id: 'acrs-001', description: 'Taxa de servi\u00e7o 10%', value: 4.50 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/addition');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'id' => 'acrs-001', 'description' => 'Taxa de servi\u00e7o 10%', 'value' => 4.50,\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/addition')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { id: 'acrs-001', description: 'Taxa de servi\u00e7o 10%', value: 4.50 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#patch-saleadditionadditionid","title":"PATCH /sale/addition/{additionId}","text":"

    Atualiza um acr\u00e9scimo existente. O id no corpo \u00e9 ignorado \u2014 vem do par\u00e2metro de rota. Retorna o acr\u00e9scimo atualizado.

    cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X PATCH http://localhost:9050/sale/addition/acrs-001 \\\n     -d '{\"value\":6.00}'\n
    await TefIP.instance.saleAddition.patch(\n  additionId: 'acrs-001',\n  addition: SaleAdditionModel(id: 'acrs-001', value: 6.00),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/addition/acrs-001', {\n  method: 'PATCH',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ value: 6.00 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/addition/acrs-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['value' => 6.00]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/addition/acrs-001')\nreq = Net::HTTP::Patch.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { value: 6.00 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#delete-saleadditionadditionid-delete-saleadditionclear","title":"DELETE /sale/addition/{additionId} \u00b7 DELETE /sale/addition/clear","text":"

    DELETE /sale/addition/{additionId} remove um acr\u00e9scimo; DELETE /sale/addition/clear remove todos. Ambos retornam o cupom completo (SaleCoupon, ver Forma das respostas).

    cURLDartJavaScriptPHPRuby
    curl -u admin:1234 -X DELETE http://localhost:9050/sale/addition/acrs-001\ncurl -u admin:1234 -X DELETE http://localhost:9050/sale/addition/clear\n
    await TefIP.instance.saleAddition.delete(additionId: 'acrs-001');\nawait TefIP.instance.saleAddition.clear();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nawait fetch('http://localhost:9050/sale/addition/acrs-001', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/addition/acrs-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/addition/acrs-001')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#post-salefinalize","title":"POST /sale/finalize","text":"

    Finaliza a venda ativa. Todos os itens e pagamentos adicionados s\u00e3o consolidados.

    Corpo da requisi\u00e7\u00e3o (opcional)

    {\n  \"message\": \"Obrigado pela compra!\",\n  \"showMessage\": true,\n  \"showCloseButton\": true,\n  \"showResultScreen\": true,\n  \"buttonCloseText\": \"Fechar\",\n  \"messageInterval\": 3000\n}\n
    Campo Tipo Padr\u00e3o Descri\u00e7\u00e3o message string null Mensagem exibida ao finalizar showMessage bool true Exibe a mensagem de finaliza\u00e7\u00e3o showCloseButton bool true Exibe bot\u00e3o para fechar a tela showResultScreen bool true Exibe a tela de resultado da venda buttonCloseText string null Texto do bot\u00e3o fechar messageInterval int 3000 Dura\u00e7\u00e3o (ms) da mensagem exibida

    Resposta \u2014 200

    { \"message\": \"Venda finalizada com sucesso\" }\n
    "},{"location":"api/sale/#exemplos-de-integracao_15","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/sale/finalize \\\n     -d '{\"message\":\"Obrigado pela compra!\",\"showMessage\":true}'\n
    await TefIP.instance.saleFinalize.post(\n  params: SaleActionRequestModel(message: 'Obrigado pela compra!'),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/finalize', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ message: 'Obrigado pela compra!', showMessage: true }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/finalize');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['message' => 'Obrigado pela compra!', 'showMessage' => true]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/finalize')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { message: 'Obrigado pela compra!', showMessage: true }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/sale/#post-salecancel","title":"POST /sale/cancel","text":"

    Cancela a venda ativa e limpa o carrinho.

    Corpo da requisi\u00e7\u00e3o (opcional)

    Mesmo formato de POST /sale/finalize.

    Resposta \u2014 200

    { \"message\": \"Venda cancelada com sucesso\" }\n
    "},{"location":"api/sale/#exemplos-de-integracao_16","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/sale/cancel\n
    await TefIP.instance.saleCancel.post();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/cancel', {\n  method: 'POST',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/cancel');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/cancel')\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/status/","title":"Status","text":"

    Endpoints para monitorar a sa\u00fade do servidor TEF IP, consultar informa\u00e7\u00f5es do dispositivo e reiniciar o aplicativo remotamente. Estes endpoints s\u00e3o sempre seguros de chamar \u2014 respondem mesmo durante pagamentos em andamento.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    Dispon\u00edveis mesmo durante opera\u00e7\u00f5es

    GET /status, GET /info e POST /restart respondem normalmente mesmo quando h\u00e1 uma opera\u00e7\u00e3o em andamento (isBusy=true). Use-os livremente para monitorar o estado do servidor sem risco de 503.

    "},{"location":"api/status/#get-status","title":"GET /status","text":"

    Verifica se o servidor est\u00e1 no ar e retorna o tempo de atividade.

    Resposta

    {\n  \"status\": \"ok\",\n  \"uptimeSeconds\": 144,\n  \"startedAt\": \"2026-01-28T16:20:53.223883\"\n}\n
    Campo Tipo Descri\u00e7\u00e3o status string Sempre \"ok\" quando o servidor responde uptimeSeconds int Segundos desde a inicializa\u00e7\u00e3o do servidor startedAt string Data/hora de in\u00edcio em formato ISO 8601"},{"location":"api/status/#exemplos-de-integracao","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     http://localhost:9050/status\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal status = await TefIP.instance.status.get();\nprint(status.uptimeSeconds);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/status', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/status');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/status')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/status/#get-info","title":"GET /info","text":"

    Retorna informa\u00e7\u00f5es detalhadas sobre o aplicativo e o dispositivo, incluindo o estado atual do servidor.

    Resposta

    {\n  \"appName\": \"TEF IP\",\n  \"version\": \"1.2.0\",\n  \"build\": \"42\",\n  \"platform\": \"android\",\n  \"locale\": \"pt_BR\",\n  \"timeZone\": \"America/Sao_Paulo\",\n  \"mode\": \"production\",\n  \"isActive\": true,\n  \"isBusy\": false\n}\n
    Campo Tipo Descri\u00e7\u00e3o appName string Nome do aplicativo version string Vers\u00e3o sem\u00e2ntica build string N\u00famero de build platform string Plataforma do dispositivo (android, windows, etc.) locale string Locale configurado no dispositivo timeZone string Fuso hor\u00e1rio do dispositivo mode string Modo de opera\u00e7\u00e3o (production, emulator) isActive bool true quando o app est\u00e1 em primeiro plano isBusy bool true quando h\u00e1 uma opera\u00e7\u00e3o em andamento (pagamento, impress\u00e3o)

    Monitorando isBusy

    Use isBusy para saber se o terminal est\u00e1 livre antes de enviar uma nova opera\u00e7\u00e3o. Requisi\u00e7\u00f5es enviadas enquanto isBusy \u00e9 true ser\u00e3o rejeitadas com 503.

    Saiba mais

    Veja Comportamento \u2192 Servidor ocupado para entender como o servidor lida com opera\u00e7\u00f5es simult\u00e2neas.

    "},{"location":"api/status/#exemplos-de-integracao_1","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     http://localhost:9050/info\n
    final info = await TefIP.instance.info.get();\nprint('${info.appName} v${info.version} \u2014 isBusy: ${info.isBusy}');\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/info', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/info');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/info')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/status/#post-restart","title":"POST /restart","text":"

    Reinicia o aplicativo TEF IP remotamente. Dispon\u00edvel apenas em dispositivos m\u00f3veis (Android ou iOS).

    Somente dispositivos m\u00f3veis

    Em plataformas n\u00e3o-m\u00f3veis (Windows, emulador de desktop), este endpoint retorna 403.

    Resposta \u2014 200

    Mesma estrutura de GET /status, refletindo o estado ap\u00f3s o rein\u00edcio.

    {\n  \"status\": \"ok\",\n  \"uptimeSeconds\": 0,\n  \"startedAt\": \"2026-03-25T10:00:00.000000\"\n}\n

    Resposta \u2014 403

    {\n  \"code\": 403,\n  \"message\": \"Reinicializa\u00e7\u00e3o dispon\u00edvel apenas para dispositivos m\u00f3veis\"\n}\n
    "},{"location":"api/status/#exemplos-de-integracao_2","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/restart\n
    final result = await TefIP.instance.restart.post();\nprint(result.status);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/restart', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/restart');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/restart')\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/swagger/","title":"Swagger / OpenAPI","text":"

    O TEF IP exp\u00f5e uma interface Swagger UI interativa e o spec OpenAPI diretamente no terminal \u2014 sem necessidade de nenhuma ferramenta externa.

    Rotas p\u00fablicas

    Os endpoints /docs e /openapi.bundle.yaml n\u00e3o exigem autentica\u00e7\u00e3o e podem ser acessados diretamente no navegador.

    "},{"location":"api/swagger/#get-docs","title":"GET /docs","text":"

    Abre a interface Swagger UI no navegador. Permite explorar e testar todos os endpoints da API de forma interativa.

    O spec \u00e9 carregado automaticamente e os servidores dispon\u00edveis s\u00e3o detectados e listados em tempo real com base nas inst\u00e2ncias ativas do TEF IP na rede.

    Como acessar:

    Abra o navegador e acesse http://<ip-do-terminal>:9050/docs.

    "},{"location":"api/swagger/#get-openapibundleyaml","title":"GET /openapi.bundle.yaml","text":"

    Retorna o spec OpenAPI completo em formato YAML. O spec inclui a lista de servidores detectados dinamicamente, incluindo o status de cada inst\u00e2ncia (Online/Offline).

    Resposta \u2014 200

    openapi: 3.0.0\ninfo:\n  title: TEF IP API\n  version: 1.0.0\n# ...\nservers:\n  - url: http://192.168.1.100:9050\n    description: Online\n  - url: http://192.168.1.101:9050\n    description: Offline\n

    O arquivo pode ser importado em qualquer ferramenta compat\u00edvel com OpenAPI (Postman, Insomnia, etc.).

    "},{"location":"api/swagger/#como-importar-no-postman","title":"Como importar no Postman","text":"
    1. Abra o Postman e clique em Import.
    2. Selecione Link e cole: http://<ip-do-terminal>:9050/openapi.bundle.yaml
    3. Clique em Continue e confirme a importa\u00e7\u00e3o.
    "},{"location":"api/swagger/#como-importar-no-insomnia","title":"Como importar no Insomnia","text":"
    1. Abra o Insomnia e clique em Create \u2192 Import from URL.
    2. Cole: http://<ip-do-terminal>:9050/openapi.bundle.yaml
    3. Confirme a importa\u00e7\u00e3o.
    "},{"location":"api/transaction/","title":"Transa\u00e7\u00f5es","text":"

    Endpoints para processar pagamentos, consultar hist\u00f3rico e realizar estornos.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    "},{"location":"api/transaction/#post-transaction","title":"POST /transaction","text":"

    Inicia um pagamento no terminal. O TEF IP aguarda o app estar em primeiro plano por at\u00e9 15 segundos antes de processar \u2014 se o app estiver minimizado, o endpoint retorna 503.

    App em segundo plano

    Se o TEF IP estiver minimizado, aguarda at\u00e9 15 s pelo retorno ao primeiro plano antes de processar \u2014 caso contr\u00e1rio retorna 503. Veja Comportamento \u2192 App em segundo plano.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"tPag\": \"17\",\n  \"amount\": 50.00,\n  \"referenceId\": \"pedido-001\",\n  \"installments\": 1,\n  \"installmentType\": \"single\",\n  \"details\": {}\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o tPag string Sim Tipo de pagamento (ver tabela abaixo) amount number Sim Valor da transa\u00e7\u00e3o referenceId string N\u00e3o Identificador externo para concilia\u00e7\u00e3o. Sem este campo, a transa\u00e7\u00e3o n\u00e3o pode ser estornada individualmente \u2014 aparece apenas na listagem geral. Use o n\u00famero do pedido ou UUID da venda. installments int N\u00e3o N\u00famero de parcelas (padr\u00e3o: 1) installmentType string N\u00e3o Modalidade de parcelamento (padr\u00e3o: \"single\") details object N\u00e3o Metadados adicionais da transa\u00e7\u00e3o

    referenceId \u00e9 necess\u00e1rio para estornos

    Sem referenceId, a transa\u00e7\u00e3o s\u00f3 aparece na listagem geral (GET /transaction) e n\u00e3o pode ser estornada individualmente. Defina-o sempre que a opera\u00e7\u00e3o puder precisar de estorno futuro.

    Valores de tPag

    Valor Descri\u00e7\u00e3o \"01\" Dinheiro \"03\" Cr\u00e9dito \"04\" D\u00e9bito \"05\" Cart\u00e3o-presente \"17\" PIX \"99\" Desconhecido

    Valores de installmentType

    Valor Descri\u00e7\u00e3o \"single\" Pagamento \u00e0 vista (padr\u00e3o) \"seller\" Parcelado pelo lojista (sem juros ao comprador) \"buyer\" Parcelado pelo comprador (juros ao comprador)

    Resposta \u2014 200

    {\n  \"nsu\": \"123456\",\n  \"cnpj\": \"05481336000137\",\n  \"cAut\": \"123456\",\n  \"txid\": null,\n  \"tBand\": \"01\",\n  \"tPag\": \"17\",\n  \"details\": {}\n}\n
    Campo Tipo Descri\u00e7\u00e3o nsu string N\u00famero sequencial \u00fanico gerado pelo adquirente cnpj string CNPJ do adquirente/emissor retornado pelo terminal cAut string C\u00f3digo de autoriza\u00e7\u00e3o \u2014 presente em cr\u00e9dito/d\u00e9bito; null em PIX txid string Identificador da transa\u00e7\u00e3o \u2014 presente apenas em PIX; null nos demais tipos tBand string Bandeira do cart\u00e3o retornada pelo adquirente tPag string C\u00f3digo do tipo de pagamento (ver tabela de tPag) details object Dados adicionais retornados pelo adquirente

    Resposta \u2014 503 (app em segundo plano)

    {\n  \"code\": 503,\n  \"message\": \"Aplicativo em segundo plano. Abra o app para concluir o pagamento.\"\n}\n
    "},{"location":"api/transaction/#exemplos-de-integracao","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/transaction \\\n     -d '{\"tPag\":\"17\",\"amount\":50.00,\"referenceId\":\"pedido-001\"}'\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal result = await TefIP.instance.transaction.post(\n  transactionRequest: TransactionRequestModel(\n    type: TefIPTransactionType.pix,\n    amount: 50.00,\n    referenceId: 'pedido-001',\n  ),\n);\nprint(result.nsu);          // NSU do adquirente\nprint(result.txid);         // preenchido em PIX\nprint(result.cAut);         // preenchido em cr\u00e9dito/d\u00e9bito\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/transaction', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ tPag: '17', amount: 50.00, referenceId: 'pedido-001' }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/transaction');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'tPag' => '17',\n    'amount' => 50.00,\n    'referenceId' => 'pedido-001',\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/transaction')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { tPag: '17', amount: 50.00, referenceId: 'pedido-001' }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/transaction/#get-transaction","title":"GET /transaction","text":"

    Lista todas as transa\u00e7\u00f5es registradas no terminal.

    Resposta \u2014 200

    Array de transa\u00e7\u00f5es, cada uma com a mesma estrutura do retorno de POST /transaction.

    [\n  {\n    \"nsu\": \"123456\",\n    \"cnpj\": \"05481336000137\",\n    \"cAut\": \"123456\",\n    \"txid\": null,\n    \"tBand\": \"01\",\n    \"tPag\": \"17\",\n    \"details\": {}\n  }\n]\n
    "},{"location":"api/transaction/#exemplos-de-integracao_1","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     http://localhost:9050/transaction\n
    final transactions = await TefIP.instance.transaction.getAll();\nfor (final t in transactions) {\n  print(t.nsu);\n}\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/transaction', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/transaction');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/transaction')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/transaction/#get-transactionreferenceid","title":"GET /transaction/{referenceId}","text":"

    Busca uma transa\u00e7\u00e3o espec\u00edfica pelo identificador externo informado no momento do pagamento.

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o referenceId string Identificador externo da transa\u00e7\u00e3o

    Resposta \u2014 200

    {\n  \"nsu\": \"123456\",\n  \"cnpj\": \"05481336000137\",\n  \"cAut\": \"123456\",\n  \"txid\": null,\n  \"tBand\": \"01\",\n  \"tPag\": \"17\",\n  \"details\": {}\n}\n
    "},{"location":"api/transaction/#exemplos-de-integracao_2","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     http://localhost:9050/transaction/pedido-001\n
    final transaction = await TefIP.instance.transaction.get(referenceId: 'pedido-001');\nprint(transaction.nsu);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/transaction/pedido-001', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$referenceId = 'pedido-001';\n$ch = curl_init(\"http://localhost:9050/transaction/{$referenceId}\");\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nreference_id = 'pedido-001'\nuri = URI(\"http://localhost:9050/transaction/#{reference_id}\")\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"api/transaction/#post-transactionreferenceidreversal","title":"POST /transaction/{referenceId}/reversal","text":"

    Realiza o estorno de uma transa\u00e7\u00e3o pelo seu referenceId. Assim como o pagamento, aguarda o app estar em primeiro plano por at\u00e9 15 segundos.

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o referenceId string Identificador externo da transa\u00e7\u00e3o a estornar

    N\u00e3o h\u00e1 corpo na requisi\u00e7\u00e3o.

    Resposta \u2014 200

    Mesma estrutura de POST /transaction.

    {\n  \"nsu\": \"123456\",\n  \"cnpj\": \"05481336000137\",\n  \"cAut\": \"123456\",\n  \"txid\": null,\n  \"tBand\": \"01\",\n  \"tPag\": \"17\",\n  \"details\": {}\n}\n

    Resposta \u2014 503 (app em segundo plano)

    {\n  \"code\": 503,\n  \"message\": \"Aplicativo em segundo plano. Abra o app para concluir o estorno.\"\n}\n
    "},{"location":"api/transaction/#exemplos-de-integracao_3","title":"Exemplos de integra\u00e7\u00e3o","text":"cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/transaction/pedido-001/reversal\n
    final result = await TefIP.instance.reversal.post(referenceId: 'pedido-001');\nprint(result.nsu);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/transaction/pedido-001/reversal', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$referenceId = 'pedido-001';\n$ch = curl_init(\"http://localhost:9050/transaction/{$referenceId}/reversal\");\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nreference_id = 'pedido-001'\nuri = URI(\"http://localhost:9050/transaction/#{reference_id}/reversal\")\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    "},{"location":"suporte/resolucao-de-problemas/","title":"Resolu\u00e7\u00e3o de Problemas","text":"

    Use este guia para resolver as situa\u00e7\u00f5es mais comuns encontradas durante a instala\u00e7\u00e3o ou opera\u00e7\u00e3o do TEF IP no dia-a-dia.

    "},{"location":"suporte/resolucao-de-problemas/#checklist-de-conectividade","title":"Checklist de Conectividade","text":"

    Se o PDV n\u00e3o conseguir se comunicar com o TEF IP, verifique:

    1. Rede: O terminal de pagamento e o computador do PDV est\u00e3o na mesma rede Wi-Fi/CABO?
    2. IP: O IP configurado no seu sistema PDV \u00e9 o mesmo que aparece na tela do app TEF IP?
    3. Basic Auth: O usu\u00e1rio e a senha configurados no seu sistema est\u00e3o corretos?
    4. Firewall: Se estiver usando Windows, a porta 9050 est\u00e1 aberta para conex\u00f5es de entrada?
    "},{"location":"suporte/resolucao-de-problemas/#mensagens-de-erro-no-terminal","title":"Mensagens de Erro no Terminal","text":""},{"location":"suporte/resolucao-de-problemas/#terminal-busy-ocupado","title":"\"Terminal Busy\" / \"Ocupado\"","text":""},{"location":"suporte/resolucao-de-problemas/#app-em-segundo-plano","title":"\"App em Segundo Plano\"","text":""},{"location":"suporte/resolucao-de-problemas/#coletando-evidencias-com-logs","title":"Coletando evid\u00eancias com logs","text":"

    Quando o comportamento n\u00e3o estiver claro, use os endpoints de logs para capturar evid\u00eancias antes de reiniciar o aplicativo:

    1. GET /logs para consultar erros recentes com filtros por n\u00edvel, origem e texto.
    2. GET /logs/stream para acompanhar eventos em tempo real enquanto reproduz o problema.
    3. GET /logs/zip/download para anexar os registros a um chamado de suporte.

    Veja os exemplos completos em Logs.

    "},{"location":"suporte/resolucao-de-problemas/#como-usar-o-restart","title":"Como usar o /restart","text":"

    O endpoint POST /restart \u00e9 uma ferramenta poderosa. Ele for\u00e7a a reinicializa\u00e7\u00e3o dos servi\u00e7os internos do servidor sem precisar fechar o app manualmente.

    Use quando: * O terminal n\u00e3o responder a novos comandos de venda mesmo estando ocioso. * Houver erros persistentes de comunica\u00e7\u00e3o com a adquirente (Stone/Rede/Getnet). * Voc\u00ea alterar configura\u00e7\u00f5es cr\u00edticas de rede no app.

    "},{"location":"suporte/versoes-requisitos/","title":"Vers\u00f5es e Requisitos","text":"

    O TEF IP \u00e9 distribu\u00eddo em vers\u00f5es espec\u00edficas para cada adquirente. Cada vers\u00e3o \u00e9 otimizada para o hardware do adquirente correspondente. Escolher a vers\u00e3o correta \u00e9 essencial para que a integra\u00e7\u00e3o com o terminal funcione.

    "},{"location":"suporte/versoes-requisitos/#versoes-disponiveis","title":"Vers\u00f5es Dispon\u00edveis","text":"Adquirente Hardware Alvo Depend\u00eancias Externas Stone SmartPOS App \"Stone SDK\" Rede SmartPOS App \"Pagamento Rede\" Getnet SmartPOS App \"Global Payments\" Emulador Windows / Android Nenhuma (perfeito para testes)"},{"location":"suporte/versoes-requisitos/#requisitos-de-instalacao","title":"Requisitos de Instala\u00e7\u00e3o","text":""},{"location":"suporte/versoes-requisitos/#no-terminal-adquirente-smartpos","title":"No Terminal Adquirente (SmartPOS)","text":"
    1. Conectividade: O terminal deve estar na mesma rede Wi-Fi que o PDV.
    2. IP Est\u00e1tico: Recomenda-se configurar um IP fixo para o terminal no roteador para evitar que o PDV perca a conex\u00e3o.
    3. Apps de Apoio: Garanta que as depend\u00eancias externas listadas na tabela acima estejam instaladas e atualizadas.
    4. Permiss\u00f5es: Ao abrir o TEF IP pela primeira vez, aceite todas as permiss\u00f5es de rede, telefone e armazenamento.
    "},{"location":"suporte/versoes-requisitos/#no-windows-emulador","title":"No Windows (Emulador)","text":"
    1. Porta 9050: Certifique-se de que a porta 9050 est\u00e1 aberta no Firewall do Windows para conex\u00f5es de entrada.
    2. Basic Auth: Configure o usu\u00e1rio e senha desejados no arquivo de configura\u00e7\u00f5es do app.
    3. Visual C++ Redistributable: Pode ser necess\u00e1rio para a execu\u00e7\u00e3o do app em algumas vers\u00f5es do Windows.

    Valida\u00e7\u00e3o p\u00f3s-instala\u00e7\u00e3o

    Depois da instala\u00e7\u00e3o, confirme o ambiente com GET /status em http://localhost:9050/status. Se a API responder, a porta, o servi\u00e7o e a autentica\u00e7\u00e3o b\u00e1sica j\u00e1 estar\u00e3o operacionais.

    "},{"location":"suporte/versoes-requisitos/#como-identificar-a-versao","title":"Como Identificar a Vers\u00e3o","text":"

    Ao abrir o aplicativo TEF IP, a vers\u00e3o e o adquirente configurado geralmente constam na tela \"Sobre\" ou no rodap\u00e9 da tela inicial. Certifique-se de que o logotipo do adquirente no app corresponde ao terminal f\u00edsico que voc\u00ea possui.

    "}]} \ No newline at end of file +{ + "config": { + "lang": [ + "pt" + ], + "separator": "[\\s\\-]+", + "pipeline": [ + "stopWordFilter" + ], + "fields": { + "title": { + "boost": 1000.0 + }, + "text": { + "boost": 1.0 + }, + "tags": { + "boost": 1000000.0 + } + } + }, + "docs": [ + { + "location": "", + "title": "TEF IP", + "text": "

    Aceite pagamentos com qualquer adquirente usando uma \u00fanica API HTTP local. Instale no terminal e comece a processar.

    " + }, + { + "location": "#como-funciona", + "title": "Como funciona", + "text": "
    flowchart LR\n    PDV[\"Seu sistema<br>(qualquer linguagem)\"]\n    tefip[\"TEF IP<br>IP Local\"]\n    HW[\"Adquirente\"]\n\n    PDV -- \"HTTP + Basic Auth\" --> tefip\n    tefip -- \"SDK do adquirente\" --> HW\n    HW -- \"aprova\u00e7\u00e3o / erro\" --> tefip\n    tefip -- \"JSON\" --> PDV

    Seu sistema faz chamadas HTTP para o TEF IP. O TEF IP se comunica com o hardware do adquirente e retorna o resultado em JSON, sem nenhuma SDK propriet\u00e1ria no seu lado.

    Sem maquininha? Use o emulador!

    O TEF IP inclui um modo emulador que simula o hardware do adquirente localmente. Voc\u00ea pode desenvolver e testar toda a integra\u00e7\u00e3o sem nenhum terminal f\u00edsico. Clique aqui para saber como usar o emulador

    Veja abaixo um pagamento sendo processado no emulador:

    " + }, + { + "location": "#o-que-voce-pode-fazer", + "title": "O que voc\u00ea pode fazer", + "text": "" + }, + { + "location": "#integracao-rapida", + "title": "Integra\u00e7\u00e3o r\u00e1pida", + "text": "

    Qualquer cliente HTTP funciona. Veja um exemplo completo, um PIX de R$ 50,00, nas linguagens mais comuns:

    cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/transaction \\\n     -d '{\"tPag\":\"17\",\"amount\":50.00,\"referenceId\":\"pedido-001\"}'\n
    import 'package:dart_tefip/dart_tefip.dart';\n\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\n\nfinal result = await TefIP.instance.transaction.post(\n  transactionRequest: TransactionRequestModel(\n    type: TefIPTransactionType.pix,\n    amount: 50.00,\n    referenceId: 'pedido-001',\n  ),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/transaction', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ tPag: '17', amount: 50.00, referenceId: 'pedido-001' }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/transaction');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'tPag' => '17',\n    'amount' => 50.00,\n    'referenceId' => 'pedido-001',\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/transaction')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { 'tPag' => '17', amount: 50.00, referenceId: 'pedido-001' }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "#adquirentes-suportados", + "title": "Adquirentes suportados", + "text": "

    Cada build do TEF IP \u00e9 compilado para um adquirente espec\u00edfico.

    " + }, + { + "location": "#sdks-disponiveis", + "title": "SDKs dispon\u00edveis", + "text": "Linguagem Pacote Status Dart / Flutter dart_tefip Dispon\u00edvel JavaScript \u2014 Sem pacote oficial no momento PHP \u2014 Sem pacote oficial no momento Ruby \u2014 Sem pacote oficial no momento

    Qualquer cliente HTTP funciona diretamente; os SDKs s\u00e3o conveni\u00eancia, n\u00e3o requisito.

    " + }, + { + "location": "#proximos-passos", + "title": "Pr\u00f3ximos Passos", + "text": "

    Novo por aqui? Comece pelo guia:

    Primeiros Passos \u2192

    Instale o TEF IP, verifique a conex\u00e3o e fa\u00e7a sua primeira requisi\u00e7\u00e3o em menos de 10 minutos.

    " + }, + { + "location": "comportamento/", + "title": "Comportamento do Servidor", + "text": "

    Esta p\u00e1gina descreve como o TEF IP se comporta em situa\u00e7\u00f5es que afetam diretamente a sua integra\u00e7\u00e3o. Leia antes de implementar os endpoints \u2014 as decis\u00f5es aqui (especialmente sobre referenceId e o comportamento de servidor ocupado) determinam se sua integra\u00e7\u00e3o vai funcionar corretamente em produ\u00e7\u00e3o.

    Leitura obrigat\u00f3ria antes de integrar

    Desenvolvedores que pulam esta p\u00e1gina frequentemente descobrem em produ\u00e7\u00e3o que n\u00e3o conseguem estornar transa\u00e7\u00f5es (por falta de referenceId) ou n\u00e3o tratam corretamente o 503 de servidor ocupado.

    " + }, + { + "location": "comportamento/#fluxo-de-uma-transacao", + "title": "Fluxo de uma transa\u00e7\u00e3o", + "text": "

    Ao enviar um pagamento, o TEF IP repassa o comando ao terminal, que interage diretamente com o portador do cart\u00e3o ou exibe o QR Code do PIX. A resposta do servidor s\u00f3 chega quando o pagamento \u00e9 aprovado, recusado ou cancelado \u2014 o que pode levar v\u00e1rios segundos dependendo da rede e do adquirente.

    Durante esse tempo o servidor fica bloqueado: nenhuma outra opera\u00e7\u00e3o pode ser enviada at\u00e9 a transa\u00e7\u00e3o ser conclu\u00edda.

    Sequ\u00eancia:

    1. PDV envia POST /transaction
    2. TEF IP repassa ao terminal do adquirente
    3. Terminal processa (cliente insere cart\u00e3o, digita senha, confirma PIX\u2026)
    4. TEF IP retorna a resposta ao PDV
    5. PDV pode enviar a pr\u00f3xima opera\u00e7\u00e3o

    Tempo de resposta

    Dimensione o timeout do seu cliente HTTP para pelo menos 60 segundos \u2014 transa\u00e7\u00f5es com cart\u00e3o f\u00edsico dependem da intera\u00e7\u00e3o do cliente no terminal.

    " + }, + { + "location": "comportamento/#identificacao-de-transacoes", + "title": "Identifica\u00e7\u00e3o de transa\u00e7\u00f5es", + "text": "

    Para consultar ou estornar uma transa\u00e7\u00e3o depois, voc\u00ea precisa de um identificador que ligue o seu sistema ao TEF IP. Esse identificador \u2014 chamado de referenceId \u2014 \u00e9 informado pelo PDV no momento do pagamento.

    Use um identificador j\u00e1 existente no seu sistema \u2014 n\u00famero do pedido, UUID da venda \u2014 qualquer valor \u00fanico serve. O TEF IP armazena esse v\u00ednculo e o devolve na resposta.

    " + }, + { + "location": "comportamento/#fluxo-de-uma-venda", + "title": "Fluxo de uma venda", + "text": "

    Uma venda \u00e9 uma sess\u00e3o aberta que agrega itens e formas de pagamento antes de ser consolidada. Apenas uma venda pode estar ativa por vez \u2014 tentar abrir uma segunda enquanto h\u00e1 uma em aberto retorna 409.

    Venda e transa\u00e7\u00e3o s\u00e3o independentes

    A venda registra o qu\u00ea foi vendido e como foi pago \u2014 mas n\u00e3o processa o pagamento financeiro. O d\u00e9bito no cart\u00e3o ou PIX \u00e9 feito separadamente via POST /transaction.

    Veja o ciclo de vida completo e os endpoints de venda \u2192

    " + }, + { + "location": "comportamento/#cancelamento-de-item-vs-exclusao", + "title": "Cancelamento de item vs. exclus\u00e3o", + "text": "

    Ao remover um item de uma venda em aberto, voc\u00ea tem duas op\u00e7\u00f5es com comportamentos distintos:

    A\u00e7\u00e3o Resultado Excluir o item Item removido permanentemente \u2014 n\u00e3o aparece no cupom/NF Cancelar o item Item mantido no hist\u00f3rico como cancelado \u2014 consta no cupom/NF com status cancelado

    Use o cancelamento quando o item precisar aparecer no documento fiscal mesmo sem ser cobrado. Use a exclus\u00e3o quando o item foi adicionado por engano e n\u00e3o deve constar em nenhum documento.

    " + }, + { + "location": "comportamento/#coleta-de-dados-no-terminal", + "title": "Coleta de dados no terminal", + "text": "

    O TEF IP pode exibir perguntas no display do terminal (CPF, texto livre, listas, e-mail, CEP\u2026) e coletar respostas sem que o PDV precise de tela pr\u00f3pria. A conex\u00e3o HTTP fica aberta at\u00e9 o usu\u00e1rio confirmar ou cancelar.

    Veja os endpoints e tipos de campo dispon\u00edveis em Perguntas (Ask) \u2192

    " + }, + { + "location": "comportamento/#servidor-ocupado", + "title": "Servidor ocupado", + "text": "

    O TEF IP processa uma opera\u00e7\u00e3o por vez. Enquanto um pagamento, estorno ou impress\u00e3o est\u00e1 em andamento, o servidor recusa novas opera\u00e7\u00f5es.

    Opera\u00e7\u00f5es que bloqueiam o servidor:

    Endpoint Opera\u00e7\u00e3o POST /transaction Pagamento em processamento POST /transaction/{referenceId}/reversal Estorno em processamento POST /print/image Impress\u00e3o de imagem em andamento POST /print/text Impress\u00e3o de texto em andamento POST /print/xml Impress\u00e3o de XML em andamento

    O que acontece ao enviar uma requisi\u00e7\u00e3o durante esse per\u00edodo:

    {\n  \"code\": 503,\n  \"message\": \"Aplicativo ocupado realizando outra opera\u00e7\u00e3o, tente mais tarde!\"\n}\n

    Como verificar se o servidor est\u00e1 livre:

    Use GET /info para consultar o estado atual. Se o servidor estiver ocupado, aguarde antes de enviar uma nova opera\u00e7\u00e3o.

    Endpoints sempre dispon\u00edveis

    GET /status, GET /info e POST /restart respondem normalmente mesmo durante uma opera\u00e7\u00e3o \u2014 use-os para monitorar o estado do servidor.

    " + }, + { + "location": "comportamento/#app-em-segundo-plano", + "title": "App em segundo plano", + "text": "

    Pagamentos e estornos exigem que o TEF IP esteja vis\u00edvel na tela do terminal. Se o operador minimizou o app, o servidor aguarda automaticamente at\u00e9 15 segundos pelo retorno ao primeiro plano.

    O que acontece:

    1. O PDV envia POST /transaction ou POST /transaction/{referenceId}/reversal.
    2. O TEF IP detecta que est\u00e1 minimizado e aguarda at\u00e9 15 s.
    3. Se o app retornar ao primeiro plano dentro do prazo, a opera\u00e7\u00e3o prossegue normalmente.
    4. Se n\u00e3o retornar, o servidor rejeita a requisi\u00e7\u00e3o:
    {\n  \"code\": 503,\n  \"message\": \"Aplicativo em segundo plano. Abra o app para concluir o pagamento.\"\n}\n

    Notifica\u00e7\u00e3o autom\u00e1tica

    Ao receber o comando, o TEF IP envia uma notifica\u00e7\u00e3o ao operador pedindo para restaurar o aplicativo. Veja a se\u00e7\u00e3o Notifica\u00e7\u00f5es ao operador abaixo.

    Como verificar se o app est\u00e1 em primeiro plano:

    Use GET /info para consultar o estado atual do aplicativo.

    " + }, + { + "location": "comportamento/#notificacoes-ao-operador", + "title": "Notifica\u00e7\u00f5es ao operador", + "text": "

    Sempre que o TEF IP recebe um comando do PDV, ele exibe automaticamente uma notifica\u00e7\u00e3o no terminal alertando o operador para restaurar o aplicativo.

    Isso \u00e9 especialmente \u00fatil quando o operador minimizou o TEF IP \u2014 a notifica\u00e7\u00e3o serve como aviso para que o app volte ao primeiro plano antes do tempo limite de 15 segundos expirar.

    Nenhuma configura\u00e7\u00e3o \u00e9 necess\u00e1ria \u2014 o comportamento \u00e9 autom\u00e1tico.

    Se o seu fluxo precisar disparar um alerta manual fora desse comportamento autom\u00e1tico, use o endpoint Notifica\u00e7\u00f5es \u2192 POST /notification.

    " + }, + { + "location": "comportamento/#endpoints-sem-autenticacao", + "title": "Endpoints sem autentica\u00e7\u00e3o", + "text": "

    A maioria dos endpoints exige Basic Auth. As \u00fanicas exce\u00e7\u00f5es s\u00e3o:

    Endpoint Descri\u00e7\u00e3o GET /docs Swagger UI GET /openapi.bundle.yaml Especifica\u00e7\u00e3o OpenAPI

    Todos os demais endpoints exigem credenciais v\u00e1lidas. Requisi\u00e7\u00f5es sem autentica\u00e7\u00e3o ou com credenciais inv\u00e1lidas recebem 401.

    " + }, + { + "location": "comportamento/#cors", + "title": "CORS", + "text": "

    O TEF IP aceita requisi\u00e7\u00f5es de qualquer origem. Nenhuma configura\u00e7\u00e3o adicional \u00e9 necess\u00e1ria para clientes web ou browser:

    " + }, + { + "location": "comportamento/#respostas-de-erro", + "title": "Respostas de erro", + "text": "

    Todos os erros retornam { \"code\": <status>, \"message\": \"...\" }. Veja a Vis\u00e3o Geral de Erros \u2192 para a refer\u00eancia completa de c\u00f3digos HTTP e sugest\u00f5es de tratamento.

    " + }, + { + "location": "emulator/", + "title": "Emulador", + "text": "

    O TEF IP inclui um modo emulador que simula o hardware do adquirente localmente \u2014 sem precisar de nenhum terminal f\u00edsico. \u00c9 a forma mais r\u00e1pida de desenvolver e testar toda a integra\u00e7\u00e3o com o TEF IP.

    N\u00e3o usar em produ\u00e7\u00e3o

    O build com emulador \u00e9 destinado exclusivamente a desenvolvimento e testes. Para uso em produ\u00e7\u00e3o, utilize o app distribu\u00eddo pelo seu adquirente no terminal Android correspondente (Stone, Getnet ou Rede).

    Veja abaixo um pagamento sendo processado no emulador:

    " + }, + { + "location": "emulator/#download", + "title": "Download", + "text": "

    Escolha a plataforma para desenvolvimento e testes:

    Plataforma Arquivo Observa\u00e7\u00e3o Windows 10+ TEF IP-emulador-setup.exe Instalador com assistente; registra o TEF IP como servi\u00e7o do Windows Android (APK) TEF IP-emulador.apk Sideload manual; n\u00e3o dispon\u00edvel na Play Store

    Onde baixar

    Os arquivos de download s\u00e3o disponibilizados pelo canal TEF IP. Entre em contato com o suporte para obter o link de download da vers\u00e3o mais recente.

    " + }, + { + "location": "emulator/#instalacao-no-windows", + "title": "Instala\u00e7\u00e3o no Windows", + "text": "
    1. Execute o instalador TEF IP-emulador-setup.exe.
    2. Siga o assistente de instala\u00e7\u00e3o (pr\u00f3ximo \u2192 pr\u00f3ximo \u2192 instalar).
    3. Ao final, o TEF IP \u00e9 registrado como servi\u00e7o do Windows e inicia automaticamente com o sistema.
    4. Um \u00edcone aparecer\u00e1 na bandeja do sistema \u2014 clique nele para abrir o painel de controle.
    " + }, + { + "location": "emulator/#_1", + "title": "Testando com Emulador", + "text": "" + }, + { + "location": "emulator/#instalacao-do-apk-android", + "title": "Instala\u00e7\u00e3o do APK Android", + "text": "
    1. No dispositivo Android, acesse Configura\u00e7\u00f5es \u2192 Seguran\u00e7a e habilite \"Fontes desconhecidas\" (ou \"Instalar apps desconhecidos\").
    2. Transfira o arquivo TEF IP-emulador.apk para o dispositivo (via USB, e-mail ou link direto).
    3. Toque no arquivo .apk para iniciar a instala\u00e7\u00e3o e confirme.
    4. Abra o app TEF IP ap\u00f3s a instala\u00e7\u00e3o.

    Dispositivo de testes

    Qualquer smartphone ou tablet Android com Android 8.0+ funciona para desenvolvimento. N\u00e3o \u00e9 necess\u00e1rio nenhum hardware de adquirente.

    " + }, + { + "location": "emulator/#proximos-passos", + "title": "Pr\u00f3ximos passos", + "text": "

    Dica de valida\u00e7\u00e3o r\u00e1pida

    Depois da instala\u00e7\u00e3o, valide o emulador com GET /status em http://localhost:9050/status usando Basic Auth. Se precisar investigar comportamento interno, consulte tamb\u00e9m Logs.

    " + }, + { + "location": "getting-started/", + "title": "Primeiros Passos", + "text": "

    Este guia leva voc\u00ea da instala\u00e7\u00e3o at\u00e9 a primeira resposta real do terminal de pagamento. Ao final, voc\u00ea ter\u00e1 o servidor rodando e confirmar\u00e1 que ele responde \u00e0s suas requisi\u00e7\u00f5es \u2014 pronto para come\u00e7ar a integrar os endpoints de pagamento.

    " + }, + { + "location": "getting-started/#pre-requisitos", + "title": "Pr\u00e9-requisitos", + "text": "" + }, + { + "location": "getting-started/#instalacao", + "title": "Instala\u00e7\u00e3o", + "text": "" + }, + { + "location": "getting-started/#terminais-android-adquirentes", + "title": "Terminais Android (Adquirentes)", + "text": "

    A instala\u00e7\u00e3o em terminais f\u00edsicos \u00e9 feita diretamente pela loja ou canal de distribui\u00e7\u00e3o do seu adquirente \u2014 o processo varia para cada um:

    Caso encontre alguma dificuldade, entre em contato com o nosso SUPORTE.

    " + }, + { + "location": "getting-started/#windows-emulador-desenvolvimentotestes", + "title": "Windows (Emulador \u2014 desenvolvimento/testes)", + "text": "
    1. Baixe o instalador .exe na p\u00e1gina do Emulador.
    2. Execute o instalador e siga o assistente de instala\u00e7\u00e3o.
    3. Ao final, o TEF IP ser\u00e1 registrado como servi\u00e7o do Windows e iniciar\u00e1 automaticamente.

    Build com emulador

    O instalador Windows dispon\u00edvel nas releases inclui o emulador de hardware \u2014 ideal para desenvolvimento e testes sem terminal f\u00edsico. Para uso em produ\u00e7\u00e3o, utilize o app distribu\u00eddo pelo seu adquirente no terminal Android correspondente.

    " + }, + { + "location": "getting-started/#emulador-apk-android-emulador-desenvolvimentotestes", + "title": "Emulador (APK Android) (Emulador \u2014 desenvolvimento/testes)", + "text": "

    O APK Android dispon\u00edvel na p\u00e1gina do Emulador \u00e9 o build com emulador de hardware \u2014 destinado a desenvolvimento e testes sem terminal f\u00edsico.

    N\u00e3o usar em produ\u00e7\u00e3o

    Este APK n\u00e3o deve ser instalado em terminais f\u00edsicos de produ\u00e7\u00e3o (Stone, Getnet, Rede). Para terminais f\u00edsicos, obtenha o app pelo canal do seu adquirente conforme descrito acima.

    " + }, + { + "location": "getting-started/#iniciando-o-servidor", + "title": "Iniciando o servidor", + "text": "

    Se for o primeiro acesso, a inicializa\u00e7\u00e3o autom\u00e1tica j\u00e1 estar\u00e1 ativa.

    Para verificar os servidores ativos:

    1. Abra o aplicativo TEF IP no terminal.
    2. Acesse a se\u00e7\u00e3o Servidores na tela inicial.
    3. Se n\u00e3o aparecer na tela inicial, abra o menu \u2192 Configura\u00e7\u00f5es \u2192 Servidores.

    Nessa tela \u00e9 poss\u00edvel visualizar os IPs detectados e executar a\u00e7\u00f5es como reiniciar ou parar os servi\u00e7os.

    " + }, + { + "location": "getting-started/#verificando-a-conexao", + "title": "Verificando a conex\u00e3o", + "text": "

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o). Os \u00fanicos endpoints sem autentica\u00e7\u00e3o s\u00e3o /docs e /openapi.bundle.yaml.

    Use o endpoint GET /status para confirmar que o servidor est\u00e1 respondendo:

    cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     http://localhost:9050/status\n
    import 'package:dart_tefip/dart_tefip.dart';\n\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\n\nfinal status = await TefIP.instance.status.get();\nprint(status);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/status', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\nconsole.log(data);\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/status');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\nprint_r($response);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/status')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\nputs data\n

    Resposta esperada:

    {\n  \"status\": \"ok\",\n  \"uptimeSeconds\": 144,\n  \"startedAt\": \"2026-01-28T16:20:53.223883\"\n}\n
    " + }, + { + "location": "getting-started/#proximos-passos", + "title": "Pr\u00f3ximos passos", + "text": "

    Com o servidor respondendo, o caminho natural \u00e9:

    1. Comportamento \u2014 entenda como o servidor lida com opera\u00e7\u00f5es simult\u00e2neas, app em segundo plano e autentica\u00e7\u00e3o antes de integrar os endpoints.
    2. Transa\u00e7\u00f5es \u2014 processe pagamentos e estornos.
    3. Vendas \u2014 monte carrinho com itens e m\u00faltiplas formas de pagamento.
    4. Swagger UI \u2014 explore e teste todos os endpoints diretamente no terminal.
    " + }, + { + "location": "sdk-dart/", + "title": "SDK Dart", + "text": "

    O dart_tefip \u00e9 o SDK oficial para Dart e Flutter. Ele encapsula as chamadas HTTP do TEF IP com modelos tipados, serializa\u00e7\u00e3o de payloads e exce\u00e7\u00f5es espec\u00edficas para a API.

    " + }, + { + "location": "sdk-dart/#instalacao", + "title": "Instala\u00e7\u00e3o", + "text": "

    Adicione ao seu pubspec.yaml:

    dependencies:\n  dart_tefip: ^<vers\u00e3o>\n

    Depois execute:

    dart pub get\n# ou\nflutter pub get\n
    " + }, + { + "location": "sdk-dart/#configuracao", + "title": "Configura\u00e7\u00e3o", + "text": "

    O SDK usa o padr\u00e3o singleton com setters est\u00e1ticos:

    import 'package:dart_tefip/dart_tefip.dart';\n\nTefIP.baseUrl = 'http://192.168.1.10:9050';\nTefIP.username = 'admin';\nTefIP.password = 'minha-senha';\n

    Para desenvolvimento local com o emulador:

    TefIP.baseUrl = 'http://localhost:9050';\n

    TefIPClient n\u00e3o existe

    N\u00e3o existe nenhuma classe TefIPClient no SDK. Use sempre TefIP.instance.

    " + }, + { + "location": "sdk-dart/#chamando-endpoints", + "title": "Chamando endpoints", + "text": "

    Todos os endpoints ficam dispon\u00edveis via TefIP.instance.<grupo>.<m\u00e9todo>(...):

    final result = await TefIP.instance.transaction.post(\n  transactionRequest: TransactionRequestModel(\n    type: TefIPTransactionType.pix,\n    amount: 50.00,\n    referenceId: 'pedido-001',\n  ),\n);\n\nprint(result.nsu);\nprint(result.txid); // PIX\nprint(result.cAut); // cr\u00e9dito/d\u00e9bito\n
    " + }, + { + "location": "sdk-dart/#catalogo-de-metodos", + "title": "Cat\u00e1logo de m\u00e9todos", + "text": "Grupo M\u00e9todos dispon\u00edveis transaction getAll(), get(referenceId:), post(transactionRequest:) reversal post(referenceId:) status get() info get() restart post() sale get(), post(request:), patch(request:), clear() saleItem post(item:), patch(itemId:, item:), delete(itemId:), cancel(itemId:), clear() salePayment post(payment:), patch(paymentId:, payment:), delete(paymentId:), clear() saleDiscount post(discount:), patch(discountId:, discount:), delete(discountId:), clear() saleAddition post(addition:), patch(additionId:, addition:), delete(additionId:), clear() saleFinalize post(), post(params:) saleCancel post(), post(params:) ask post(questionRequest:) askForm post(form:) askCancel post() displayImage post(imageData:) displayText post(displayTextRequest:) displayCarousel post(displayCarouselRequest:) displayClear post() displayPop post() printImage post(imageData:) printText post(text:) printXml post(xml:) log getAll(level:, source:, dateFrom:, dateTo:, limit:, search:, includeDetails:), stream(), downloadZip(level:, source:, dateFrom:, dateTo:, limit:) notification post(request:)

    Sem accessor para ACBr

    O SDK Dart atual n\u00e3o exp\u00f5e um m\u00e9todo dedicado para POST /print/acbr. Para esse endpoint, use HTTP direto.

    " + }, + { + "location": "sdk-dart/#exemplos-rapidos", + "title": "Exemplos r\u00e1pidos", + "text": "" + }, + { + "location": "sdk-dart/#venda", + "title": "Venda", + "text": "
    await TefIP.instance.sale.post(\n  request: SaleStartRequestModel(\n    customerName: 'Jo\u00e3o Silva',\n    total: 99.90,\n  ),\n);\n\nawait TefIP.instance.saleItem.post(\n  item: SaleItemModel(\n    code: '123',\n    description: 'Coca-Cola 2L',\n    quantity: 1,\n    unitPrice: 10.00,\n  ),\n);\n
    " + }, + { + "location": "sdk-dart/#ask", + "title": "Ask", + "text": "
    final answer = await TefIP.instance.ask.post(\n  questionRequest: AskSingleQuestionRequestModel(\n    question: AskQuestionModel(type: TefIPQuestionType.cpfOrcnpj),\n    parameters: AskParametersModel(),\n  ),\n);\n\nprint(answer.value);\n
    " + }, + { + "location": "sdk-dart/#display", + "title": "Display", + "text": "
    await TefIP.instance.displayText.post(\n  displayTextRequest: DisplayTextRequestModel(\n    content: [\n      {'text': 'Aguardando operador'},\n    ],\n    backgroundColor: 'white',\n    showCloseButton: false,\n  ),\n);\n
    " + }, + { + "location": "sdk-dart/#logs", + "title": "Logs", + "text": "
    final logs = await TefIP.instance.log.getAll(\n  level: TefIPLogLevel.error,\n  limit: 50,\n);\n\nTefIP.instance.log.stream().listen((log) {\n  print('[${log.level.name}] ${log.message}');\n});\n
    " + }, + { + "location": "sdk-dart/#notificacoes", + "title": "Notifica\u00e7\u00f5es", + "text": "
    await TefIP.instance.notification.post(\n  request: NotificationRequestModel(\n    title: 'Novo pagamento',\n    message: 'Restaure o aplicativo para processar',\n  ),\n);\n
    " + }, + { + "location": "sdk-dart/#timeout", + "title": "Timeout", + "text": "

    Por padr\u00e3o, o SDK n\u00e3o define timeout global. Isso \u00e9 \u00fatil para fluxos de pagamento em que o terminal pode aguardar intera\u00e7\u00e3o do operador ou do cliente por tempo indeterminado.

    Para definir um timeout global:

    TefIP.requestsTimeOut = const Duration(minutes: 2);\n

    Tamb\u00e9m \u00e9 poss\u00edvel passar timeout: em chamadas que suportam override por requisi\u00e7\u00e3o.

    " + }, + { + "location": "sdk-dart/#tratamento-de-excecoes", + "title": "Tratamento de exce\u00e7\u00f5es", + "text": "

    Todo m\u00e9todo do SDK pode lan\u00e7ar dois tipos de exce\u00e7\u00e3o:

    try {\n  final result = await TefIP.instance.transaction.post(\n    transactionRequest: TransactionRequestModel(\n      type: TefIPTransactionType.pix,\n      amount: 50.00,\n    ),\n  );\n  print(result.nsu);\n} on TefIPRequestException catch (e) {\n  print(e.statusCode);\n  print(e.message);\n  print(e.rawBody);\n} on TefIPUnexpectedException catch (e) {\n  print(e.exception);\n}\n
    Exce\u00e7\u00e3o Quando ocorre Campos TefIPRequestException API retornou 4xx/5xx ou falha de conex\u00e3o tratada statusCode, message, rawBody? TefIPUnexpectedException Erro inesperado fora do fluxo HTTP padr\u00e3o exception" + }, + { + "location": "sdk-dart/#referencia-de-enums", + "title": "Refer\u00eancia de enums", + "text": "" + }, + { + "location": "sdk-dart/#tefiptransactiontype", + "title": "TefIPTransactionType", + "text": "Valor tPag Descri\u00e7\u00e3o TefIPTransactionType.money \"01\" Dinheiro TefIPTransactionType.credit \"03\" Cr\u00e9dito TefIPTransactionType.debit \"04\" D\u00e9bito TefIPTransactionType.pix \"17\" PIX TefIPTransactionType.unknown \"99\" Desconhecido" + }, + { + "location": "sdk-dart/#tefipinstallmenttype", + "title": "TefIPInstallmentType", + "text": "Valor Descri\u00e7\u00e3o TefIPInstallmentType.single \u00c0 vista TefIPInstallmentType.seller Parcelado pelo lojista TefIPInstallmentType.buyer Parcelado pelo comprador" + }, + { + "location": "sdk-dart/#tefiptransactionstatus", + "title": "TefIPTransactionStatus", + "text": "Valor Descri\u00e7\u00e3o TefIPTransactionStatus.pending Pendente TefIPTransactionStatus.paid Pago TefIPTransactionStatus.cancelled Cancelado TefIPTransactionStatus.unknown Desconhecido" + }, + { + "location": "sdk-dart/#tefipsalepaymenttype", + "title": "TefIPSalePaymentType", + "text": "Valor Descri\u00e7\u00e3o TefIPSalePaymentType.money Dinheiro TefIPSalePaymentType.credit Cr\u00e9dito TefIPSalePaymentType.debit D\u00e9bito TefIPSalePaymentType.gift Cart\u00e3o-presente TefIPSalePaymentType.pix PIX TefIPSalePaymentType.veroWallet Carteira digital Vero TefIPSalePaymentType.voucher Voucher TefIPSalePaymentType.adm Opera\u00e7\u00e3o administrativa TefIPSalePaymentType.cancel Cancelamento de pagamento TefIPSalePaymentType.cancelDigitalWallet Cancelamento de carteira digital TefIPSalePaymentType.unknown Desconhecido" + }, + { + "location": "sdk-dart/#tefipquestiontype", + "title": "TefIPQuestionType", + "text": "Valor Descri\u00e7\u00e3o TefIPQuestionType.list Lista de op\u00e7\u00f5es TefIPQuestionType.button Bot\u00f5es de op\u00e7\u00e3o TefIPQuestionType.text Texto livre TefIPQuestionType.phone Telefone TefIPQuestionType.number Somente n\u00fameros TefIPQuestionType.cpf CPF TefIPQuestionType.cnpj CNPJ TefIPQuestionType.cpfOrcnpj CPF ou CNPJ TefIPQuestionType.email E-mail TefIPQuestionType.cep CEP TefIPQuestionType.date Data TefIPQuestionType.time Hora TefIPQuestionType.money Valor monet\u00e1rio TefIPQuestionType.regex Regex personalizada" + }, + { + "location": "sdk-dart/#tefipcarouseltransition", + "title": "TefIPCarouselTransition", + "text": "Valor Descri\u00e7\u00e3o TefIPCarouselTransition.fade Dissolve entre imagens TefIPCarouselTransition.slide Desliza entre imagens TefIPCarouselTransition.none Troca instant\u00e2nea" + }, + { + "location": "sdk-js/", + "title": "SDK JavaScript", + "text": "

    N\u00e3o existe pacote oficial JavaScript para o TEF IP neste momento.

    Enquanto isso, a integra\u00e7\u00e3o recomendada \u00e9 chamar a API diretamente com fetch ou qualquer cliente HTTP equivalente, usando Basic Auth.

    const res = await fetch('http://localhost:9050/status', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\n\nconst data = await res.json();\n

    Os exemplos completos por endpoint est\u00e3o nas p\u00e1ginas de API Reference. O panorama geral fica em SDKs.

    " + }, + { + "location": "sdk-php/", + "title": "SDK PHP", + "text": "

    N\u00e3o existe pacote oficial PHP para o TEF IP neste momento.

    Enquanto isso, a integra\u00e7\u00e3o recomendada \u00e9 chamar a API diretamente com curl ou outro cliente HTTP, usando Basic Auth.

    <?php\n$ch = curl_init('http://localhost:9050/status');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n

    Os exemplos completos por endpoint est\u00e3o nas p\u00e1ginas de API Reference. O panorama geral fica em SDKs.

    " + }, + { + "location": "sdk-ruby/", + "title": "SDK Ruby", + "text": "

    N\u00e3o existe pacote oficial Ruby para o TEF IP neste momento.

    Enquanto isso, a integra\u00e7\u00e3o recomendada \u00e9 chamar a API diretamente com Net::HTTP ou outro cliente HTTP, usando Basic Auth.

    require 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/status')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n

    Os exemplos completos por endpoint est\u00e3o nas p\u00e1ginas de API Reference. O panorama geral fica em SDKs.

    " + }, + { + "location": "sdks/", + "title": "SDKs", + "text": "

    Os SDKs do TEF IP s\u00e3o opcionais. A API continua sendo HTTP puro com Basic Auth, ent\u00e3o qualquer linguagem pode integrar diretamente mesmo sem pacote dedicado.

    " + }, + { + "location": "sdks/#panorama-atual", + "title": "Panorama atual", + "text": "Linguagem Pacote oficial Status Documenta\u00e7\u00e3o Dart / Flutter dart_tefip Dispon\u00edvel SDK Dart JavaScript N\u00e3o Sem pacote oficial no momento SDK JavaScript PHP N\u00e3o Sem pacote oficial no momento SDK PHP Ruby N\u00e3o Sem pacote oficial no momento SDK Ruby" + }, + { + "location": "sdks/#quando-usar-sdk", + "title": "Quando usar SDK", + "text": "Cen\u00e1rio Recomenda\u00e7\u00e3o App Flutter ou Dart Use o dart_tefip Backend ou PDV em outra linguagem Use HTTP direto Integra\u00e7\u00e3o r\u00e1pida ou prova de conceito Pode come\u00e7ar por cURL/fetch/curl/Net::HTTP

    Todas as p\u00e1ginas de API Reference incluem exemplos prontos em cURL, Dart, JavaScript, PHP e Ruby.

    " + }, + { + "location": "api/ask/", + "title": "Perguntas (Ask)", + "text": "

    Endpoints para exibir perguntas interativas na tela do terminal e coletar respostas do cliente \u2014 CPF, e-mail, texto livre, listas de op\u00e7\u00f5es e muito mais.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    " + }, + { + "location": "api/ask/#como-funciona", + "title": "Como funciona", + "text": "

    A requisi\u00e7\u00e3o HTTP fica aberta at\u00e9 o usu\u00e1rio confirmar ou cancelar no terminal \u2014 ou o PDV enviar POST /ask/cancel. Use Pergunta \u00danica (/ask) para campos avulsos e Formul\u00e1rio (/ask/form) para coletar v\u00e1rios campos em sequ\u00eancia; as respostas chegam todas juntas ao final.

    Timeout

    Configure o timeout do cliente para pelo menos 60 segundos, pois a resposta depende da intera\u00e7\u00e3o humana no terminal.

    " + }, + { + "location": "api/ask/#post-ask", + "title": "POST /ask", + "text": "

    Exibe uma \u00fanica pergunta na tela do terminal e aguarda a resposta do cliente.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"parameters\": {\n    \"buttonText\": \"Confirmar\",\n    \"showCancelButton\": false,\n    \"buttonCancelText\": \"Cancelar\",\n    \"showSuccessMessage\": false,\n    \"successMessage\": null,\n    \"successMessageInterval\": 3000,\n    \"confirmAnswer\": false\n  },\n  \"question\": {\n    \"id\": 0,\n    \"question\": \"Informe seu CPF\",\n    \"type\": \"CPF\",\n    \"required\": false,\n    \"minLength\": 0,\n    \"maxLength\": 255,\n    \"defaultValue\": null,\n    \"mask\": null,\n    \"regex\": null,\n    \"errorMessage\": null,\n    \"options\": null\n  }\n}\n

    Campos de parameters

    Campo Tipo Padr\u00e3o Descri\u00e7\u00e3o buttonText string \"Confirmar\" Texto do bot\u00e3o de confirma\u00e7\u00e3o showCancelButton bool false Exibe bot\u00e3o de cancelamento buttonCancelText string \"Cancelar\" Texto do bot\u00e3o de cancelamento showSuccessMessage bool false Exibe tela de sucesso ap\u00f3s confirma\u00e7\u00e3o successMessage string null Mensagem de sucesso personalizada successMessageInterval int 3000 Dura\u00e7\u00e3o (ms) da tela de sucesso confirmAnswer bool false Exige confirma\u00e7\u00e3o antes de submeter a resposta

    Campos de question

    Campo Tipo Padr\u00e3o Descri\u00e7\u00e3o id int 0 Identificador da pergunta question string null Texto exibido na tela (se null, usa prompt padr\u00e3o do tipo) type string \"TEXT\" Tipo de entrada (ver tabela abaixo) required bool false Resposta obrigat\u00f3ria minLength int 0 Comprimento m\u00ednimo da resposta maxLength int 255 Comprimento m\u00e1ximo da resposta defaultValue string null Valor pr\u00e9-preenchido no campo mask string null M\u00e1scara de entrada (ex.: \"###.###.###-##\") regex string null Regex de valida\u00e7\u00e3o personalizado errorMessage string null Mensagem de erro quando a valida\u00e7\u00e3o falha options array null Op\u00e7\u00f5es selecion\u00e1veis (obrigat\u00f3rio para LIST e BUTTON)

    Tipos de entrada (type)

    Valor Descri\u00e7\u00e3o \"TEXT\" Texto livre \"NUMBER\" Somente n\u00fameros \"PHONE\" N\u00famero de telefone \"CPF\" CPF (com valida\u00e7\u00e3o) \"CNPJ\" CNPJ (com valida\u00e7\u00e3o) \"CPFORCNPJ\" CPF ou CNPJ \"EMAIL\" E-mail (com valida\u00e7\u00e3o) \"CEP\" CEP (com valida\u00e7\u00e3o) \"DATE\" Data \"TIME\" Hora \"MONEY\" Valor monet\u00e1rio \"REGEX\" Valida\u00e7\u00e3o por regex personalizado \"LIST\" Lista de op\u00e7\u00f5es (requer options) \"BUTTON\" Bot\u00f5es de op\u00e7\u00e3o (requer options)

    Formato de options (obrigat\u00f3rio para LIST e BUTTON)

    [\n  { \"id\": 1, \"name\": \"Sim\", \"value\": \"sim\" },\n  { \"id\": 2, \"name\": \"N\u00e3o\", \"value\": \"nao\" }\n]\n
    Campo Tipo Descri\u00e7\u00e3o id int Identificador \u00fanico da op\u00e7\u00e3o name string Texto exibido na tela value string Valor retornado quando a op\u00e7\u00e3o \u00e9 selecionada

    Resposta \u2014 200

    {\n  \"id\": 0,\n  \"value\": \"12345678900\"\n}\n
    Campo Tipo Descri\u00e7\u00e3o id int Identificador da pergunta respondida value string Resposta fornecida pelo cliente" + }, + { + "location": "api/ask/#exemplos-de-integracao", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/ask \\\n     -d '{\n       \"parameters\": { \"buttonText\": \"Confirmar\" },\n       \"question\": { \"type\": \"CPF\", \"question\": \"Informe seu CPF\" }\n     }'\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal answer = await TefIP.instance.ask.post(\n  questionRequest: AskSingleQuestionRequestModel(\n    parameters: AskParametersModel(buttonText: 'Confirmar'),\n    question: AskQuestionModel(\n      question: 'Informe seu CPF',\n      type: TefIPQuestionType.cpf,\n    ),\n  ),\n);\nprint(answer.value);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/ask', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    parameters: { buttonText: 'Confirmar' },\n    question: { type: 'CPF', question: 'Informe seu CPF' },\n  }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/ask');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'parameters' => ['buttonText' => 'Confirmar'],\n    'question'   => ['type' => 'CPF', 'question' => 'Informe seu CPF'],\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/ask')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = {\n  parameters: { buttonText: 'Confirmar' },\n  question: { type: 'CPF', question: 'Informe seu CPF' },\n}.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/ask/#post-askform", + "title": "POST /ask/form", + "text": "

    Exibe um formul\u00e1rio com m\u00faltiplas perguntas em sequ\u00eancia. O cliente responde cada uma antes de passar para a pr\u00f3xima.

    IDs autom\u00e1ticos

    Se todas as perguntas tiverem id: 0, o TEF IP atribui IDs sequenciais automaticamente (0, 1, 2\u2026). Se quiser IDs personalizados, cada pergunta deve ter um id \u00fanico \u2014 duplicatas retornam 400.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"parameters\": {\n    \"buttonText\": \"Pr\u00f3ximo\",\n    \"showCancelButton\": true,\n    \"buttonCancelText\": \"Cancelar\"\n  },\n  \"questions\": [\n    {\n      \"id\": 1,\n      \"question\": \"Nome completo\",\n      \"type\": \"TEXT\",\n      \"required\": true\n    },\n    {\n      \"id\": 2,\n      \"question\": \"CPF\",\n      \"type\": \"CPF\",\n      \"required\": true\n    },\n    {\n      \"id\": 3,\n      \"question\": \"Como prefere pagar?\",\n      \"type\": \"LIST\",\n      \"options\": [\n        { \"id\": 1, \"name\": \"Cr\u00e9dito\", \"value\": \"credit\" },\n        { \"id\": 2, \"name\": \"D\u00e9bito\",  \"value\": \"debit\"  },\n        { \"id\": 3, \"name\": \"PIX\",     \"value\": \"pix\"    }\n      ]\n    }\n  ]\n}\n

    Resposta \u2014 200

    Array com a resposta de cada pergunta, na mesma ordem.

    [\n  { \"id\": 1, \"value\": \"Jo\u00e3o Silva\" },\n  { \"id\": 2, \"value\": \"12345678900\" },\n  { \"id\": 3, \"value\": \"pix\" }\n]\n

    Resposta \u2014 400

    { \"code\": 400, \"message\": \"Nenhuma pergunta recebida\" }\n
    { \"code\": 400, \"message\": \"Existem perguntas com IDs duplicados no formul\u00e1rio\" }\n

    " + }, + { + "location": "api/ask/#exemplos-de-integracao_1", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/ask/form \\\n     -d '{\n       \"parameters\": { \"buttonText\": \"Pr\u00f3ximo\" },\n       \"questions\": [\n         { \"id\": 1, \"question\": \"Nome\", \"type\": \"TEXT\" },\n         { \"id\": 2, \"question\": \"CPF\",  \"type\": \"CPF\"  }\n       ]\n     }'\n
    final answers = await TefIP.instance.askForm.post(\n  form: AskFormRequestModel(\n    parameters: AskParametersModel(buttonText: 'Pr\u00f3ximo'),\n    questions: [\n      AskQuestionModel(id: 1, question: 'Nome', type: TefIPQuestionType.text),\n      AskQuestionModel(id: 2, question: 'CPF',  type: TefIPQuestionType.cpf),\n    ],\n  ),\n);\nfor (final a in answers) {\n  print('${a.id}: ${a.value}');\n}\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/ask/form', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    parameters: { buttonText: 'Pr\u00f3ximo' },\n    questions: [\n      { id: 1, question: 'Nome', type: 'TEXT' },\n      { id: 2, question: 'CPF',  type: 'CPF'  },\n    ],\n  }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/ask/form');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'parameters' => ['buttonText' => 'Pr\u00f3ximo'],\n    'questions'  => [\n        ['id' => 1, 'question' => 'Nome', 'type' => 'TEXT'],\n        ['id' => 2, 'question' => 'CPF',  'type' => 'CPF' ],\n    ],\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/ask/form')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = {\n  parameters: { buttonText: 'Pr\u00f3ximo' },\n  questions: [\n    { id: 1, question: 'Nome', type: 'TEXT' },\n    { id: 2, question: 'CPF',  type: 'CPF'  },\n  ],\n}.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/ask/#post-askcancel", + "title": "POST /ask/cancel", + "text": "

    Cancela a pergunta ou formul\u00e1rio em exibi\u00e7\u00e3o no momento.

    N\u00e3o h\u00e1 corpo na requisi\u00e7\u00e3o.

    Resposta \u2014 200

    {\n  \"message\": \"Pergunta cancelada com sucesso\"\n}\n
    " + }, + { + "location": "api/ask/#exemplos-de-integracao_2", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/ask/cancel\n
    await TefIP.instance.askCancel.post();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/ask/cancel', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/ask/cancel');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/ask/cancel')\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/display/", + "title": "Display", + "text": "

    Endpoints para controlar a tela do terminal \u2014 exibir imagens, textos formatados, carross\u00e9is e limpar o display.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    " + }, + { + "location": "api/display/#quando-usar-o-display", + "title": "Quando usar o display", + "text": "

    O display \u00e9 um canal independente do fluxo de pagamento \u2014 exibir conte\u00fado n\u00e3o bloqueia nem interfere com transa\u00e7\u00f5es. Use-o para comunica\u00e7\u00e3o visual com o cliente:

    Ao finalizar ou cancelar uma venda (POST /sale/finalize / POST /sale/cancel), o TEF IP limpa o display automaticamente.

    " + }, + { + "location": "api/display/#post-displayimage", + "title": "POST /display/image", + "text": "

    Exibe uma imagem em tela cheia na tela do terminal.

    Corpo da requisi\u00e7\u00e3o

    Bytes bin\u00e1rios da imagem, enviados diretamente no corpo da requisi\u00e7\u00e3o.

    Header Valor Content-Type application/octet-stream

    Resposta \u2014 200

    { \"message\": \"Imagem exibida com sucesso\" }\n

    Resposta \u2014 400 (nenhuma imagem enviada)

    { \"code\": 400, \"message\": \"Nenhuma imagem enviada\" }\n

    Resposta \u2014 500 (erro ao exibir)

    { \"code\": 500, \"message\": \"Erro ao exibir imagem\" }\n
    " + }, + { + "location": "api/display/#exemplos-de-integracao", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/octet-stream\" \\\n     -X POST http://localhost:9050/display/image \\\n     --data-binary @imagem.png\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nimport 'dart:io';\n\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal imageData = await File('imagem.png').readAsBytes();\nawait TefIP.instance.displayImage.post(imageData: imageData);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst imageBytes = await fetch('/imagem.png').then(r => r.arrayBuffer());\nconst res = await fetch('http://localhost:9050/display/image', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/octet-stream',\n  },\n  body: imageBytes,\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$imageData = file_get_contents('imagem.png');\n$ch = curl_init('http://localhost:9050/display/image');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/octet-stream']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, $imageData);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nimage_data = File.binread('imagem.png')\nuri = URI('http://localhost:9050/display/image')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/octet-stream')\nreq.basic_auth('admin', '1234')\nreq.body = image_data\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/display/#post-displaytext", + "title": "POST /display/text", + "text": "

    Exibe conte\u00fado de texto formatado na tela do terminal.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"content\": [\n    { \"text\": { \"value\": \"Bem-vindo!\", \"size\": 24, \"bold\": true, \"align\": \"center\" } },\n    { \"line\": { \"divider\": true } },\n    { \"text\": { \"value\": \"Aguarde o atendimento.\", \"size\": 16, \"align\": \"center\" } }\n  ],\n  \"backgroundColor\": \"#FFFFFF\",\n  \"showCloseButton\": true\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o content array Sim Instru\u00e7\u00f5es de layout (ver formato abaixo) backgroundColor string N\u00e3o Cor de fundo em hex (padr\u00e3o: \"#FFFFFF\") showCloseButton bool N\u00e3o Exibe bot\u00e3o para fechar a tela

    Formato de content

    Cada item do array \u00e9 um objeto com uma chave identificando o tipo de elemento:

    Tipo Exemplo Texto { \"text\": { \"value\": \"Ol\u00e1\", \"size\": 18, \"bold\": false, \"align\": \"left\" } } Divisor { \"line\": { \"divider\": true } }

    Resposta \u2014 200

    { \"message\": \"Texto exibido com sucesso\" }\n
    " + }, + { + "location": "api/display/#exemplos-de-integracao_1", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/display/text \\\n     -d '{\n       \"content\": [\n         { \"text\": { \"value\": \"Bem-vindo!\", \"size\": 24, \"bold\": true, \"align\": \"center\" } }\n       ],\n       \"backgroundColor\": \"#FFFFFF\",\n       \"showCloseButton\": true\n     }'\n
    await TefIP.instance.displayText.post(\n  displayTextRequest: DisplayTextRequestModel(\n    content: [\n      {'text': {'value': 'Bem-vindo!', 'size': 24, 'bold': true, 'align': 'center'}},\n    ],\n    backgroundColor: '#FFFFFF',\n    showCloseButton: true,\n  ),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/display/text', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    content: [\n      { text: { value: 'Bem-vindo!', size: 24, bold: true, align: 'center' } },\n    ],\n    backgroundColor: '#FFFFFF',\n    showCloseButton: true,\n  }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/display/text');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'content' => [\n        ['text' => ['value' => 'Bem-vindo!', 'size' => 24, 'bold' => true, 'align' => 'center']],\n    ],\n    'backgroundColor' => '#FFFFFF',\n    'showCloseButton' => true,\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/display/text')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = {\n  content: [\n    { text: { value: 'Bem-vindo!', size: 24, bold: true, align: 'center' } },\n  ],\n  backgroundColor: '#FFFFFF',\n  showCloseButton: true,\n}.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/display/#post-displaycarousel", + "title": "POST /display/carousel", + "text": "

    Exibe um carrossel de imagens na tela do terminal, alternando automaticamente em intervalos configur\u00e1veis.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"images\": [\n    \"<base64 da imagem 1>\",\n    \"<base64 da imagem 2>\"\n  ],\n  \"intervalMs\": 3000,\n  \"transition\": \"fade\",\n  \"backgroundColor\": \"#000000\",\n  \"showCloseButton\": false\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o images array de string Sim Imagens em Base64 (pelo menos uma) intervalMs int N\u00e3o Intervalo entre imagens em ms (padr\u00e3o: 3000) transition string N\u00e3o Anima\u00e7\u00e3o de transi\u00e7\u00e3o (padr\u00e3o: \"fade\") backgroundColor string N\u00e3o Cor de fundo em hex (padr\u00e3o: \"#FFFFFF\") showCloseButton bool N\u00e3o Exibe bot\u00e3o para fechar (padr\u00e3o: false)

    Valores de transition

    Valor Descri\u00e7\u00e3o \"fade\" Transi\u00e7\u00e3o por dissolu\u00e7\u00e3o (padr\u00e3o) \"slide\" Transi\u00e7\u00e3o por deslizamento \"none\" Sem anima\u00e7\u00e3o de transi\u00e7\u00e3o

    Resposta \u2014 200

    { \"message\": \"Carousel exibido com sucesso\" }\n
    " + }, + { + "location": "api/display/#exemplos-de-integracao_2", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    # Converta as imagens para Base64 antes de enviar\nIMG1=$(base64 -w 0 imagem1.png)\nIMG2=$(base64 -w 0 imagem2.png)\n\ncurl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/display/carousel \\\n     -d \"{\\\"images\\\":[\\\"$IMG1\\\",\\\"$IMG2\\\"],\\\"intervalMs\\\":3000,\\\"transition\\\":\\\"fade\\\",\\\"backgroundColor\\\":\\\"#000000\\\"}\"\n
    import 'dart:io';\n\nfinal img1 = await File('imagem1.png').readAsBytes();\nfinal img2 = await File('imagem2.png').readAsBytes();\nawait TefIP.instance.displayCarousel.post(\n  displayCarouselRequest: DisplayCarouselRequestModel(\n    images: [img1, img2],\n    intervalMs: 3000,\n    transition: TefIPCarouselTransition.fade,\n    backgroundColor: '#000000',\n  ),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nasync function fileToBase64(file) {\n  return new Promise((resolve) => {\n    const reader = new FileReader();\n    reader.onload = () => resolve(reader.result.split(',')[1]);\n    reader.readAsDataURL(file);\n  });\n}\n\nconst img1 = await fileToBase64(imagemFile1);\nconst img2 = await fileToBase64(imagemFile2);\n\nconst res = await fetch('http://localhost:9050/display/carousel', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    images: [img1, img2],\n    intervalMs: 3000,\n    transition: 'fade',\n    backgroundColor: '#000000',\n  }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$img1 = base64_encode(file_get_contents('imagem1.png'));\n$img2 = base64_encode(file_get_contents('imagem2.png'));\n\n$ch = curl_init('http://localhost:9050/display/carousel');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'images'          => [$img1, $img2],\n    'intervalMs'      => 3000,\n    'transition'      => 'fade',\n    'backgroundColor' => '#000000',\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\nrequire 'base64'\n\nimg1 = Base64.strict_encode64(File.binread('imagem1.png'))\nimg2 = Base64.strict_encode64(File.binread('imagem2.png'))\n\nuri = URI('http://localhost:9050/display/carousel')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = {\n  images: [img1, img2],\n  intervalMs: 3000,\n  transition: 'fade',\n  backgroundColor: '#000000',\n}.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/display/#post-displayclear", + "title": "POST /display/clear", + "text": "

    Remove qualquer conte\u00fado exibido na tela do terminal e retorna ao estado padr\u00e3o.

    N\u00e3o h\u00e1 corpo na requisi\u00e7\u00e3o.

    Resposta \u2014 200

    { \"message\": \"Display limpo com sucesso\" }\n
    " + }, + { + "location": "api/display/#exemplos-de-integracao_3", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/display/clear\n
    await TefIP.instance.displayClear.post();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/display/clear', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/display/clear');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/display/clear')\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/display/#post-displaypop", + "title": "POST /display/pop", + "text": "

    Fecha a sobreposi\u00e7\u00e3o atualmente exibida na tela, voltando \u00e0 tela anterior sem limpar o estado completo.

    N\u00e3o h\u00e1 corpo na requisi\u00e7\u00e3o.

    Resposta \u2014 200

    { \"message\": \"Display fechado com sucesso\" }\n
    " + }, + { + "location": "api/display/#exemplos-de-integracao_4", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/display/pop\n
    await TefIP.instance.displayPop.post();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/display/pop', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/display/pop');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/display/pop')\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/erros/", + "title": "C\u00f3digos de Erro", + "text": "

    O TEF IP utiliza c\u00f3digos de status HTTP padr\u00e3o para indicar o sucesso ou falha de uma requisi\u00e7\u00e3o. Todas as respostas de erro acompanham um corpo JSON com detalhes adicionais.

    " + }, + { + "location": "api/erros/#formato-de-erro", + "title": "Formato de Erro", + "text": "
    {\n  \"code\": 400,\n  \"message\": \"Mensagem descritiva do erro\"\n}\n
    " + }, + { + "location": "api/erros/#tabela-de-referencia", + "title": "Tabela de Refer\u00eancia", + "text": "C\u00f3digo Nome Significado para o Integrador 200 OK A opera\u00e7\u00e3o foi processada com sucesso. 204 No Content Sucesso, mas n\u00e3o h\u00e1 conte\u00fado de retorno (ex.: respostas de CORS). 400 Bad Request O corpo da requisi\u00e7\u00e3o (JSON/XML/Bin\u00e1rio) \u00e9 inv\u00e1lido ou faltam campos obrigat\u00f3rios. 401 Unauthorized As credenciais de Basic Auth est\u00e3o ausentes ou incorretas. 403 Forbidden A opera\u00e7\u00e3o foi recusada pela adquirente ou as permiss\u00f5es s\u00e3o insuficientes (ex.: /restart em plataforma n\u00e3o-m\u00f3vel). 404 Not Found Recurso inexistente: venda, item, pagamento, desconto ou acr\u00e9scimo n\u00e3o encontrado, ou nenhuma pergunta ativa em /ask/cancel. 409 Conflict Voc\u00ea tentou iniciar uma opera\u00e7\u00e3o que conflita com o estado atual (ex.: iniciar venda com outra aberta). 499 Cancelled Pergunta/formul\u00e1rio (/ask, /ask/form) cancelado pelo usu\u00e1rio ou via /ask/cancel. 500 Internal Error Ocorreu um erro inesperado no servidor. Verifique os logs do dispositivo. 503 Service Unavailable O servidor est\u00e1 ocupado (isBusy) ou o aplicativo est\u00e1 em segundo plano (isActive = false)." + }, + { + "location": "api/erros/#sugestoes-de-tratamento", + "title": "Sugest\u00f5es de Tratamento", + "text": "" + }, + { + "location": "api/logs/", + "title": "Logs", + "text": "

    Endpoints para consultar, acompanhar em tempo real e exportar os logs do TEF IP. Eles ajudam a investigar falhas de integra\u00e7\u00e3o, comportamento do servidor e eventos de roteamento HTTP.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    Quando usar cada endpoint

    Use GET /logs para an\u00e1lise pontual, GET /logs/stream para monitoramento em tempo real e GET /logs/zip/download quando precisar anexar os registros a um chamado ou auditoria.

    " + }, + { + "location": "api/logs/#get-logs", + "title": "GET /logs", + "text": "

    Retorna uma lista de logs, com suporte a filtros por n\u00edvel, origem, intervalo de datas e texto.

    Query parameters

    Par\u00e2metro Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o level string N\u00e3o N\u00edvel do log: fatal, error, warning, info, trace, path, debug source string N\u00e3o Origem do log: app, router, http dateFrom string N\u00e3o Data/hora inicial em ISO 8601 dateTo string N\u00e3o Data/hora final em ISO 8601 limit int N\u00e3o N\u00famero m\u00e1ximo de registros retornados search string N\u00e3o Busca parcial em message e details

    Resposta

    [\n  {\n    \"id\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n    \"level\": \"error\",\n    \"source\": \"http\",\n    \"message\": \"POST /transaction retornou 500\",\n    \"details\": \"Exception: connection refused\\n  at ...\",\n    \"createdAt\": \"2024-06-15T14:30:00.000Z\"\n  }\n]\n
    Campo Tipo Descri\u00e7\u00e3o id string Identificador \u00fanico do log level string Severidade do evento source string Origem do log message string Mensagem principal details string | null Detalhes adicionais, como stack trace ou payload createdAt string Data/hora em ISO 8601" + }, + { + "location": "api/logs/#exemplos-de-integracao", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     \"http://localhost:9050/logs?level=error&source=http&limit=50&search=timeout\"\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal logs = await TefIP.instance.log.getAll(\n  level: TefIPLogLevel.error,\n  source: TefIPLogSource.http,\n  limit: 50,\n  search: 'timeout',\n);\nprint(logs.first.message);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/logs?level=error&source=http&limit=50&search=timeout', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/logs?level=error&source=http&limit=50&search=timeout');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/logs?level=error&source=http&limit=50&search=timeout')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/logs/#get-logszipdownload", + "title": "GET /logs/zip/download", + "text": "

    Exporta os logs filtrados como um arquivo ZIP. O arquivo retornado cont\u00e9m tefip_logs.log em texto plano.

    Query parameters

    Os mesmos filtros de GET /logs s\u00e3o aceitos, exceto search.

    Resposta \u2014 200

    Header Valor Content-Type application/zip Content-Disposition attachment; filename=\"tefip_logs.zip\"" + }, + { + "location": "api/logs/#exemplos-de-integracao_1", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -o tefip_logs.zip \\\n     \"http://localhost:9050/logs/zip/download?level=error&limit=200\"\n
    import 'dart:io';\n\nfinal zipBytes = await TefIP.instance.log.downloadZip(\n  level: TefIPLogLevel.error,\n  limit: 200,\n);\nawait File('tefip_logs.zip').writeAsBytes(zipBytes);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/logs/zip/download?level=error&limit=200', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst blob = await res.blob();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/logs/zip/download?level=error&limit=200');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$zipBytes = curl_exec($ch);\ncurl_close($ch);\nfile_put_contents('tefip_logs.zip', $zipBytes);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\n\nuri = URI('http://localhost:9050/logs/zip/download?level=error&limit=200')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\nFile.binwrite('tefip_logs.zip', res.body)\n
    " + }, + { + "location": "api/logs/#get-logsstream", + "title": "GET /logs/stream", + "text": "

    Abre uma conex\u00e3o SSE (Server-Sent Events) e envia um novo evento para cada log gerado enquanto a conex\u00e3o estiver aberta.

    Resposta

    data: {\"id\":\"abc\",\"level\":\"info\",\"source\":\"http\",\"message\":\"POST /transaction 200\",\"details\":null,\"createdAt\":\"2024-06-15T14:30:00.000Z\"}\n
    Header Valor Content-Type text/event-stream Cache-Control no-cache X-Accel-Buffering no" + }, + { + "location": "api/logs/#exemplos-de-integracao_2", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -N -u admin:1234 \\\n     http://localhost:9050/logs/stream\n
    TefIP.instance.log.stream().listen((log) {\n  print('[${log.level.name}] ${log.message}');\n});\n
    // TODO: EventSource n\u00e3o permite definir Authorization; para browser, prefira um proxy autenticado\nconst res = await fetch('http://localhost:9050/logs/stream', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\n\nconst reader = res.body.getReader();\nconst decoder = new TextDecoder();\n\nwhile (true) {\n  const { done, value } = await reader.read();\n  if (done) break;\n  console.log(decoder.decode(value, { stream: true }));\n}\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/logs/stream');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($curl, $chunk) {\n    echo $chunk;\n    return strlen($chunk);\n});\ncurl_exec($ch);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\n\nuri = URI('http://localhost:9050/logs/stream')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\n\nNet::HTTP.start(uri.hostname, uri.port) do |http|\n  http.request(req) do |res|\n    res.read_body do |chunk|\n      puts chunk\n    end\n  end\nend\n
    " + }, + { + "location": "api/notification/", + "title": "Notifica\u00e7\u00f5es", + "text": "

    Endpoint para disparar uma notifica\u00e7\u00e3o local no dispositivo que executa o TEF IP. \u00c9 \u00fatil para chamar o operador de volta ao app ou sinalizar um evento importante no fluxo de pagamento.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    Comportamento no Android

    Em dispositivos Android, o TEF IP acorda a tela antes de exibir a notifica\u00e7\u00e3o.

    " + }, + { + "location": "api/notification/#post-notification", + "title": "POST /notification", + "text": "

    Envia uma notifica\u00e7\u00e3o local com t\u00edtulo e mensagem.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"title\": \"Novo pagamento\",\n  \"message\": \"Restaure o aplicativo para processar\"\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o title string Sim T\u00edtulo da notifica\u00e7\u00e3o message string Sim Corpo da notifica\u00e7\u00e3o

    Resposta \u2014 200

    {\n  \"message\": \"Notifica\u00e7\u00e3o enviada com sucesso\"\n}\n

    Resposta \u2014 400

    {\n  \"code\": 400,\n  \"message\": \"Corpo da requisi\u00e7\u00e3o inv\u00e1lido\"\n}\n
    " + }, + { + "location": "api/notification/#exemplos-de-integracao", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/notification \\\n     -d '{\"title\":\"Novo pagamento\",\"message\":\"Restaure o aplicativo para processar\"}'\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nawait TefIP.instance.notification.post(\n  request: NotificationRequestModel(\n    title: 'Novo pagamento',\n    message: 'Restaure o aplicativo para processar',\n  ),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/notification', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    title: 'Novo pagamento',\n    message: 'Restaure o aplicativo para processar',\n  }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/notification');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'title' => 'Novo pagamento',\n    'message' => 'Restaure o aplicativo para processar',\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/notification')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = {\n  title: 'Novo pagamento',\n  message: 'Restaure o aplicativo para processar',\n}.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/print/", + "title": "Impress\u00e3o", + "text": "

    Endpoints para imprimir imagens, comprovantes formatados e cupons fiscais (XML/DANFE) na impressora do terminal.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    Bloqueio durante impress\u00e3o

    Todos os endpoints de impress\u00e3o definem isBusy = true enquanto a opera\u00e7\u00e3o est\u00e1 em andamento. Novas requisi\u00e7\u00f5es que verificam o estado ocupado ser\u00e3o rejeitadas com 503.

    " + }, + { + "location": "api/print/#impressao-fiscal-danfexml", + "title": "Impress\u00e3o Fiscal (DANFE/XML)", + "text": "

    O TEF IP inclui um parser avan\u00e7ado para documentos fiscais eletr\u00f4nicos. Ao inv\u00e9s de o seu sistema formatar o comprovante manualmente, voc\u00ea pode enviar o XML original da nota e o terminal cuidar\u00e1 da renderiza\u00e7\u00e3o.

    " + }, + { + "location": "api/print/#funcionamento-do-parser", + "title": "Funcionamento do Parser", + "text": "

    O servidor processa o XML e mapeia campos como: * Dados do Emitente: Nome, CNPJ, Inscri\u00e7\u00e3o Estadual, Endere\u00e7o. * Dados do Destinat\u00e1rio: Nome/Raz\u00e3o Social, CPF/CNPJ. * Itens: Descri\u00e7\u00e3o, quantidade, valor unit\u00e1rio e total. * Totais: BC ICMS, Valor ICMS, Valor Total da Nota. * Informa\u00e7\u00f5es de Pagamento: Formas de pagamento utilizadas. * Protocolo de Autoriza\u00e7\u00e3o: N\u00famero, data e hora da autoriza\u00e7\u00e3o.

    " + }, + { + "location": "api/print/#requisitos-do-xml", + "title": "Requisitos do XML", + "text": "

    Para que a impress\u00e3o ocorra sem erros, o XML deve: 1. Seguir o padr\u00e3o nacional de NF-e/NFC-e (vers\u00e3o 4.00). 2. Estar completo e conter as tags de protocolo de autoriza\u00e7\u00e3o (<protNFe> ou <protCTe>). 3. Ser enviado com o header Content-Type: text/xml.

    Customiza\u00e7\u00e3o

    Se precisar de um layout muito espec\u00edfico ou marcas pr\u00f3prias que n\u00e3o constam no XML, utilize o endpoint POST /print/text para montar o comprovante linha por linha.

    " + }, + { + "location": "api/print/#post-printimage", + "title": "POST /print/image", + "text": "

    Imprime uma imagem diretamente na impressora do terminal.

    Corpo da requisi\u00e7\u00e3o

    Bytes bin\u00e1rios da imagem, enviados diretamente no corpo da requisi\u00e7\u00e3o.

    Header Valor Content-Type application/octet-stream

    Resposta \u2014 200

    { \"message\": \"Impress\u00e3o realizada com sucesso\" }\n

    Resposta \u2014 400 (nenhuma imagem enviada)

    { \"code\": 400, \"message\": \"Nenhuma imagem enviada\" }\n

    Resposta \u2014 500 (erro na impress\u00e3o)

    { \"code\": 500, \"message\": \"Erro ao imprimir\" }\n
    " + }, + { + "location": "api/print/#exemplos-de-integracao", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/octet-stream\" \\\n     -X POST http://localhost:9050/print/image \\\n     --data-binary @comprovante.png\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nimport 'dart:io';\n\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal imageData = await File('comprovante.png').readAsBytes();\nawait TefIP.instance.printImage.post(imageData: imageData);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst imageBytes = await fetch('/comprovante.png').then(r => r.arrayBuffer());\nconst res = await fetch('http://localhost:9050/print/image', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/octet-stream',\n  },\n  body: imageBytes,\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$imageData = file_get_contents('comprovante.png');\n$ch = curl_init('http://localhost:9050/print/image');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/octet-stream']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, $imageData);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nimage_data = File.binread('comprovante.png')\nuri = URI('http://localhost:9050/print/image')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/octet-stream')\nreq.basic_auth('admin', '1234')\nreq.body = image_data\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/print/#post-printtext", + "title": "POST /print/text", + "text": "

    Imprime um comprovante com formata\u00e7\u00e3o personalizada. O corpo \u00e9 um array JSON de instru\u00e7\u00f5es de impress\u00e3o.

    Corpo da requisi\u00e7\u00e3o

    [\n  { \"text\": { \"value\": \"COMPROVANTE\", \"size\": 20, \"bold\": true,  \"align\": \"center\" } },\n  { \"line\": { \"divider\": true } },\n  { \"text\": { \"value\": \"Produto: Coca-Cola\",  \"size\": 14, \"bold\": false, \"align\": \"left\" } },\n  { \"text\": { \"value\": \"Valor:   R$ 5,00\",    \"size\": 14, \"bold\": false, \"align\": \"left\" } },\n  { \"line\": { \"divider\": true } },\n  { \"text\": { \"value\": \"Obrigado pela compra!\", \"size\": 14, \"bold\": false, \"align\": \"center\" } }\n]\n

    Cada item do array define um elemento de impress\u00e3o pela sua chave de tipo:

    Tipo Exemplo Texto { \"text\": { \"value\": \"...\", \"size\": 16, \"bold\": false, \"align\": \"left\" } } Divisor { \"line\": { \"divider\": true } }

    Resposta \u2014 200

    { \"message\": \"Impress\u00e3o realizada com sucesso\" }\n

    Resposta \u2014 400 (nenhum conte\u00fado enviado)

    { \"code\": 500, \"message\": \"Nenhum texto enviado\" }\n
    " + }, + { + "location": "api/print/#exemplos-de-integracao_1", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/print/text \\\n     -d '[\n       {\"text\": {\"value\": \"COMPROVANTE\", \"size\": 20, \"bold\": true, \"align\": \"center\"}},\n       {\"line\": {\"divider\": true}},\n       {\"text\": {\"value\": \"Obrigado!\", \"size\": 14, \"bold\": false, \"align\": \"center\"}}\n     ]'\n
    await TefIP.instance.printText.post(\n  text: [\n    {'text': {'value': 'COMPROVANTE', 'size': 20, 'bold': true,  'align': 'center'}},\n    {'line': {'divider': true}},\n    {'text': {'value': 'Obrigado!',   'size': 14, 'bold': false, 'align': 'center'}},\n  ],\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/print/text', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify([\n    { text: { value: 'COMPROVANTE', size: 20, bold: true,  align: 'center' } },\n    { line: { divider: true } },\n    { text: { value: 'Obrigado!',   size: 14, bold: false, align: 'center' } },\n  ]),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/print/text');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    ['text' => ['value' => 'COMPROVANTE', 'size' => 20, 'bold' => true,  'align' => 'center']],\n    ['line' => ['divider' => true]],\n    ['text' => ['value' => 'Obrigado!',   'size' => 14, 'bold' => false, 'align' => 'center']],\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/print/text')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = [\n  { text: { value: 'COMPROVANTE', size: 20, bold: true,  align: 'center' } },\n  { line: { divider: true } },\n  { text: { value: 'Obrigado!',   size: 14, bold: false, align: 'center' } },\n].to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/print/#post-printxml", + "title": "POST /print/xml", + "text": "

    Imprime um cupom fiscal a partir de um XML de NF-e/DANFE. O TEF IP faz o parse do XML e renderiza automaticamente o layout do cupom fiscal.

    Corpo da requisi\u00e7\u00e3o

    String com o conte\u00fado do XML da NF-e.

    Header Valor Content-Type text/xml
    <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<nfeProc xmlns=\"http://www.portalfiscal.inf.br/nfe\" versao=\"4.00\">\n  ...\n</nfeProc>\n

    Resposta \u2014 200

    { \"message\": \"Impress\u00e3o realizada com sucesso\" }\n

    Resposta \u2014 400 (nenhum XML enviado)

    { \"code\": 403, \"message\": \"Nenhum XML enviado\" }\n

    Resposta \u2014 500 (erro na impress\u00e3o)

    { \"code\": 500, \"message\": \"Erro ao imprimir\" }\n
    " + }, + { + "location": "api/print/#exemplos-de-integracao_2", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: text/xml\" \\\n     -X POST http://localhost:9050/print/xml \\\n     --data-binary @nota-fiscal.xml\n
    import 'dart:io';\n\nfinal xml = await File('nota-fiscal.xml').readAsString();\nawait TefIP.instance.printXml.post(xml: xml);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst xml = await fetch('/nota-fiscal.xml').then(r => r.text());\nconst res = await fetch('http://localhost:9050/print/xml', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'text/xml',\n  },\n  body: xml,\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$xml = file_get_contents('nota-fiscal.xml');\n$ch = curl_init('http://localhost:9050/print/xml');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: text/xml']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, $xml);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nxml = File.read('nota-fiscal.xml')\nuri = URI('http://localhost:9050/print/xml')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'text/xml')\nreq.basic_auth('admin', '1234')\nreq.body = xml\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/print/#post-printacbr", + "title": "POST /print/acbr", + "text": "

    Imprime um layout descrito no formato de tags ACBr \u2014 texto puro enviado diretamente no corpo da requisi\u00e7\u00e3o (sem JSON). \u00datil para reaproveitar layouts de PDV j\u00e1 escritos nesse padr\u00e3o.

    Corpo da requisi\u00e7\u00e3o

    Texto puro com as tags ACBr.

    Header Valor Content-Type text/plain

    Tags suportadas

    Categoria Tags Estilo <n> negrito \u00b7 <i> it\u00e1lico \u00b7 <s> sublinhado \u00b7 <in> invertido \u00b7 <e> expandido \u00b7 <c> condensado \u00b7 <a> altura dupla Alinhamento </ce> centro \u00b7 </ae> esquerda \u00b7 </ad> direita Estrutura </zera> reset \u00b7 </fn> fonte normal \u00b7 </linha_simples> e </linha_dupla> divis\u00f3rias \u00b7 <qrcode>...</qrcode> QR Code

    Tags ignoradas

    </corte_total>, </corte> e </logo> s\u00e3o aceitas, mas n\u00e3o produzem efeito no terminal.

    Resposta \u2014 200

    { \"message\": \"Impress\u00e3o realizada com sucesso\" }\n

    Resposta \u2014 400 (nenhum conte\u00fado enviado)

    { \"code\": 400, \"message\": \"Nenhum conte\u00fado enviado\" }\n

    Resposta \u2014 500 (erro na impress\u00e3o)

    { \"code\": 500, \"message\": \"Erro ao imprimir\" }\n
    " + }, + { + "location": "api/print/#exemplos-de-integracao_3", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: text/plain\" \\\n     -X POST http://localhost:9050/print/acbr \\\n     --data-binary $'</ce><n>TEF IP</n>\\n</ae>Obrigado pela compra!\\n</linha_simples>'\n
    // TODO: o SDK Dart ainda n\u00e3o exp\u00f5e m\u00e9todo para ACBr \u2014 usando http diretamente\nimport 'package:http/http.dart' as http;\n\nfinal layout = '</ce><n>TEF IP</n>\\n</ae>Obrigado pela compra!\\n</linha_simples>';\nawait http.post(\n  Uri.parse('http://localhost:9050/print/acbr'),\n  headers: {\n    'Authorization': 'Basic ${base64Encode(utf8.encode('admin:1234'))}',\n    'Content-Type': 'text/plain',\n  },\n  body: layout,\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst layout = '</ce><n>TEF IP</n>\\n</ae>Obrigado pela compra!\\n</linha_simples>';\nconst res = await fetch('http://localhost:9050/print/acbr', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'text/plain',\n  },\n  body: layout,\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$layout = \"</ce><n>TEF IP</n>\\n</ae>Obrigado pela compra!\\n</linha_simples>\";\n$ch = curl_init('http://localhost:9050/print/acbr');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: text/plain']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, $layout);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nlayout = \"</ce><n>TEF IP</n>\\n</ae>Obrigado pela compra!\\n</linha_simples>\"\nuri = URI('http://localhost:9050/print/acbr')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'text/plain')\nreq.basic_auth('admin', '1234')\nreq.body = layout\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/", + "title": "Venda", + "text": "

    Endpoints para gerenciar vendas: abrir um carrinho, adicionar itens e pagamentos, e finalizar ou cancelar a venda. A venda organiza o que foi vendido \u2014 o pagamento financeiro \u00e9 feito separadamente via POST /transaction.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    Fluxo de venda

    Uma venda segue a sequ\u00eancia: iniciar \u2192 adicionar itens \u2192 adicionar pagamentos \u2192 finalizar (ou cancelar). Apenas uma venda pode estar ativa por vez.

    " + }, + { + "location": "api/sale/#ciclo-de-vida-da-venda", + "title": "Ciclo de Vida da Venda", + "text": "

    Diferente de uma transa\u00e7\u00e3o avulsa, uma Venda no TEF IP \u00e9 uma sess\u00e3o que acumula itens e pagamentos antes de ser consolidada. O servidor gerencia o estado dessa venda internamente.

    " + }, + { + "location": "api/sale/#fluxo-de-estados", + "title": "Fluxo de Estados", + "text": "
    stateDiagram-v2\n    [*] --> Aberta: POST /sale\n    Aberta --> Aberta: itens (POST/PATCH/DELETE /sale/item \u00b7 cancel \u00b7 clear)\n    Aberta --> Aberta: pagamentos (POST/PATCH/DELETE /sale/payment \u00b7 clear)\n    Aberta --> Aberta: descontos (POST/PATCH/DELETE /sale/discount \u00b7 clear)\n    Aberta --> Aberta: acr\u00e9scimos (POST/PATCH/DELETE /sale/addition \u00b7 clear)\n    Aberta --> Finalizada: POST /sale/finalize\n    Aberta --> Cancelada: POST /sale/cancel\n    Finalizada --> [*]\n    Cancelada --> [*]
    " + }, + { + "location": "api/sale/#regras-importantes", + "title": "Regras Importantes", + "text": "
    1. Exclusividade: Apenas uma venda pode estar ativa por vez no dispositivo. Tentar iniciar uma nova sem encerrar a anterior resulta em erro 409 Conflict.
    2. Sincroniza\u00e7\u00e3o: Opera\u00e7\u00f5es de venda s\u00e3o s\u00edncronas. O servidor retorna a confirma\u00e7\u00e3o assim que o estado interno \u00e9 atualizado.
    3. Documento Fiscal: Os itens e pagamentos adicionados servem de base para a montagem de cupons fiscais e DANFE.
    4. Pagamento financeiro: A venda registra o qu\u00ea foi vendido e como foi pago \u2014 mas n\u00e3o processa o d\u00e9bito financeiro. O pagamento no cart\u00e3o ou PIX \u00e9 feito separadamente via POST /transaction. Finalize a venda ap\u00f3s confirmar a aprova\u00e7\u00e3o da transa\u00e7\u00e3o.
    5. Limpeza: Ao finalizar ou cancelar, o TEF IP limpa automaticamente qualquer conte\u00fado que esteja sendo exibido no visor do terminal (pop de displays).
    " + }, + { + "location": "api/sale/#forma-das-respostas", + "title": "Forma das respostas", + "text": "

    As rotas de venda seguem uma conven\u00e7\u00e3o consistente:

    O cupom completo (SaleCoupon) tem o seguinte formato:

    {\n  \"sale\": {\n    \"customerDocument\": \"123.456.789-00\",\n    \"customerName\": \"Jo\u00e3o Silva\",\n    \"sellerName\": \"Maria\",\n    \"additionalInfo\": \"Balc\u00e3o 3\",\n    \"total\": null\n  },\n  \"items\": [],\n  \"payments\": [],\n  \"discounts\": [],\n  \"additions\": [],\n  \"summary\": {\n    \"subtotal\": 0,\n    \"surcharge\": 0,\n    \"discount\": 0,\n    \"itemDiscount\": 0,\n    \"itemAddition\": 0,\n    \"total\": 0\n  }\n}\n

    Valores monet\u00e1rios em reais

    Todos os valores (unitPrice, total, value, discount, addition, etc.) trafegam em reais decimais (ex.: 10.50), n\u00e3o em centavos. Descontos e acr\u00e9scimos s\u00e3o armazenados em m\u00f3dulo (valor absoluto): enviar -5.00 \u00e9 equivalente a 5.00.

    " + }, + { + "location": "api/sale/#get-sale", + "title": "GET /sale", + "text": "

    Retorna o estado da venda ativa (o cupom completo). \u00datil para sincronizar o carrinho a qualquer momento.

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    " + }, + { + "location": "api/sale/#exemplos-de-integracao", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     http://localhost:9050/sale\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal coupon = await TefIP.instance.sale.get();\nprint('Total: ${coupon.summary.total}');\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale', {\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#post-sale", + "title": "POST /sale", + "text": "

    Inicia uma nova venda. Retorna 409 se j\u00e1 existir uma venda ativa.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"customerDocument\": \"123.456.789-00\",\n  \"customerName\": \"Jo\u00e3o Silva\",\n  \"sellerName\": \"Maria\",\n  \"additionalInfo\": \"Balc\u00e3o 3\"\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o customerDocument string N\u00e3o CPF ou CNPJ do cliente customerName string N\u00e3o Nome do cliente exibido no terminal sellerName string N\u00e3o Nome do vendedor exibido no terminal additionalInfo string N\u00e3o Informa\u00e7\u00e3o adicional exibida no terminal total number N\u00e3o Valor total a exibir na tela de venda

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    Resposta \u2014 409 (j\u00e1 existe uma venda ativa)

    { \"code\": 409, \"message\": \"J\u00e1 existe uma venda ativa!\" }\n
    " + }, + { + "location": "api/sale/#exemplos-de-integracao_1", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/sale \\\n     -d '{\"customerName\":\"Jo\u00e3o Silva\",\"sellerName\":\"Maria\"}'\n
    final coupon = await TefIP.instance.sale.post(\n  request: SaleStartRequestModel(\n    customerName: 'Jo\u00e3o Silva',\n    sellerName: 'Maria',\n  ),\n);\nprint('Itens: ${coupon.items.length}');\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ customerName: 'Jo\u00e3o Silva', sellerName: 'Maria' }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'customerName' => 'Jo\u00e3o Silva',\n    'sellerName'   => 'Maria',\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { customerName: 'Jo\u00e3o Silva', sellerName: 'Maria' }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#patch-sale", + "title": "PATCH /sale", + "text": "

    Atualiza os dados da venda ativa (cliente, vendedor, informa\u00e7\u00f5es adicionais). Usa o mesmo corpo que POST /sale.

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    " + }, + { + "location": "api/sale/#exemplos-de-integracao_2", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X PATCH http://localhost:9050/sale \\\n     -d '{\"customerName\":\"Maria Souza\"}'\n
    await TefIP.instance.sale.patch(\n  request: SaleStartRequestModel(customerName: 'Maria Souza'),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale', {\n  method: 'PATCH',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ customerName: 'Maria Souza' }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['customerName' => 'Maria Souza']));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale')\nreq = Net::HTTP::Patch.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { customerName: 'Maria Souza' }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#delete-saleclear", + "title": "DELETE /sale/clear", + "text": "

    Esvazia a venda ativa por completo \u2014 remove todos os itens, pagamentos, descontos e acr\u00e9scimos, preservando o cabe\u00e7alho (cliente/vendedor).

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon) j\u00e1 esvaziado (ver Forma das respostas).

    " + }, + { + "location": "api/sale/#exemplos-de-integracao_3", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X DELETE http://localhost:9050/sale/clear\n
    await TefIP.instance.sale.clear();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/clear', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/clear');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/clear')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#post-saleitem", + "title": "POST /sale/item", + "text": "

    Adiciona um item ao carrinho da venda ativa.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"id\": \"item-001\",\n  \"code\": \"7891234567890\",\n  \"description\": \"Coca-Cola 350ml\",\n  \"canceled\": false,\n  \"quantity\": 2.0,\n  \"unitPrice\": 5.00,\n  \"discount\": 0.50,\n  \"addition\": null,\n  \"total\": 9.50,\n  \"additionalInfo\": null\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o id string Sim Identificador \u00fanico do item code string Sim C\u00f3digo do produto (ex.: EAN/c\u00f3digo de barras) description string Sim Descri\u00e7\u00e3o exibida no terminal canceled bool N\u00e3o Item marcado como cancelado (padr\u00e3o: false) quantity number Sim Quantidade unitPrice number Sim Pre\u00e7o unit\u00e1rio (reais) discount number N\u00e3o Desconto aplicado ao item (m\u00f3dulo) addition number N\u00e3o Acr\u00e9scimo aplicado ao item total number Sim Valor total do item (reais) additionalInfo string N\u00e3o Informa\u00e7\u00e3o adicional

    Resposta \u2014 200

    Retorna o item criado (mesmo formato do corpo da requisi\u00e7\u00e3o).

    {\n  \"id\": \"item-001\",\n  \"code\": \"7891234567890\",\n  \"description\": \"Coca-Cola 350ml\",\n  \"canceled\": false,\n  \"quantity\": 2.0,\n  \"unitPrice\": 5.00,\n  \"discount\": 0.50,\n  \"addition\": null,\n  \"total\": 9.50,\n  \"additionalInfo\": null\n}\n

    Resposta \u2014 400 (item duplicado)

    { \"code\": 400, \"message\": \"Item j\u00e1 existente na venda!\" }\n
    " + }, + { + "location": "api/sale/#exemplos-de-integracao_4", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/sale/item \\\n     -d '{\"id\":\"item-001\",\"code\":\"7891234567890\",\"description\":\"Coca-Cola 350ml\",\"quantity\":2,\"unitPrice\":5.00,\"total\":9.50}'\n
    final item = await TefIP.instance.saleItem.post(\n  item: SaleItemModel(\n    id: 'item-001',\n    code: '7891234567890',\n    description: 'Coca-Cola 350ml',\n    quantity: 2,\n    unitPrice: 5.00,\n    total: 9.50,\n  ),\n);\nprint(item.id);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/item', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    id: 'item-001',\n    code: '7891234567890',\n    description: 'Coca-Cola 350ml',\n    quantity: 2,\n    unitPrice: 5.00,\n    total: 9.50,\n  }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/item');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'id'          => 'item-001',\n    'code'        => '7891234567890',\n    'description' => 'Coca-Cola 350ml',\n    'quantity'    => 2,\n    'unitPrice'   => 5.00,\n    'total'       => 9.50,\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/item')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = {\n  id: 'item-001', code: '7891234567890', description: 'Coca-Cola 350ml',\n  quantity: 2, unitPrice: 5.00, total: 9.50,\n}.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#patch-saleitemitemid", + "title": "PATCH /sale/item/{itemId}", + "text": "

    Atualiza os dados de um item j\u00e1 adicionado \u00e0 venda. O id no corpo \u00e9 ignorado \u2014 o identificador vem do par\u00e2metro de rota.

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o itemId string Identificador do item a atualizar

    Corpo igual ao de POST /sale/item. O id no corpo \u00e9 ignorado \u2014 o identificador vem do par\u00e2metro de rota.

    Resposta \u2014 200

    Retorna o item atualizado (mesmo formato do corpo da requisi\u00e7\u00e3o).

    " + }, + { + "location": "api/sale/#exemplos-de-integracao_5", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X PATCH http://localhost:9050/sale/item/item-001 \\\n     -d '{\"code\":\"7891234567890\",\"description\":\"Coca-Cola 350ml\",\"quantity\":3,\"unitPrice\":5.00,\"total\":14.50}'\n
    await TefIP.instance.saleItem.patch(\n  itemId: 'item-001',\n  item: SaleItemModel(\n    code: '7891234567890',\n    description: 'Coca-Cola 350ml',\n    quantity: 3,\n    unitPrice: 5.00,\n    total: 14.50,\n  ),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/item/item-001', {\n  method: 'PATCH',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ code: '7891234567890', description: 'Coca-Cola 350ml', quantity: 3, unitPrice: 5.00, total: 14.50 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/item/item-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'code' => '7891234567890', 'description' => 'Coca-Cola 350ml',\n    'quantity' => 3, 'unitPrice' => 5.00, 'total' => 14.50,\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/item/item-001')\nreq = Net::HTTP::Patch.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { code: '7891234567890', description: 'Coca-Cola 350ml', quantity: 3, unitPrice: 5.00, total: 14.50 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#delete-saleitemclear", + "title": "DELETE /sale/item/clear", + "text": "

    Remove todos os itens da venda ativa, preservando pagamentos, descontos e acr\u00e9scimos.

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    " + }, + { + "location": "api/sale/#exemplos-de-integracao_6", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X DELETE http://localhost:9050/sale/item/clear\n
    await TefIP.instance.saleItem.clear();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/item/clear', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/item/clear');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/item/clear')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#delete-saleitemitemid", + "title": "DELETE /sale/item/{itemId}", + "text": "

    Remove um item permanentemente do carrinho da venda ativa.

    Cancel vs Delete

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o itemId string Identificador do item a remover

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    " + }, + { + "location": "api/sale/#exemplos-de-integracao_7", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X DELETE http://localhost:9050/sale/item/item-001\n
    await TefIP.instance.saleItem.delete(itemId: 'item-001');\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/item/item-001', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/item/item-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/item/item-001')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#post-saleitemitemidcancel", + "title": "POST /sale/item/{itemId}/cancel", + "text": "

    Marca um item como cancelado sem remov\u00ea-lo do carrinho. \u00datil para manter o hist\u00f3rico da venda.

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o itemId string Identificador do item a cancelar

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon) com o item marcado como canceled: true (ver Forma das respostas).

    " + }, + { + "location": "api/sale/#exemplos-de-integracao_8", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/sale/item/item-001/cancel\n
    await TefIP.instance.saleItem.cancel(itemId: 'item-001');\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/item/item-001/cancel', {\n  method: 'POST',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/item/item-001/cancel');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/item/item-001/cancel')\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#post-salepayment", + "title": "POST /sale/payment", + "text": "

    Adiciona uma forma de pagamento \u00e0 venda ativa.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"id\": \"pgto-001\",\n  \"tPag\": \"17\",\n  \"description\": null,\n  \"value\": 50.00,\n  \"additionalInfo\": null\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o id string Sim Identificador \u00fanico do pagamento tPag string N\u00e3o C\u00f3digo do tipo de pagamento (ver tabela abaixo; padr\u00e3o \"99\") description string N\u00e3o Descri\u00e7\u00e3o exibida no terminal value number Sim Valor do pagamento (reais) additionalInfo string N\u00e3o Informa\u00e7\u00e3o adicional

    Valores de tPag (c\u00f3digo num\u00e9rico \u2014 o mesmo c\u00f3digo da adquirente)

    C\u00f3digo (tPag) Enum SDK Descri\u00e7\u00e3o \"01\" money Dinheiro \"03\" credit Cr\u00e9dito \"04\" debit D\u00e9bito \"05\" gift Cart\u00e3o-presente \"17\" pix \u00b7 veroWallet PIX / Carteira digital Vero \"99\" unknown \u00b7 voucher \u00b7 adm \u00b7 cancel \u00b7 cancelDigitalWallet Demais tipos

    Envie o c\u00f3digo num\u00e9rico, n\u00e3o o nome

    No JSON cru, tPag deve ser o c\u00f3digo num\u00e9rico (\"17\"), n\u00e3o o nome (\"pix\"). Um nome n\u00e3o reconhecido \u00e9 interpretado como \"99\" (desconhecido). No SDK Dart, use o enum TefIPSalePaymentType.pix \u2014 ele converte para o c\u00f3digo automaticamente.

    Resposta \u2014 200

    Retorna o pagamento criado (mesmo formato do corpo, com tPag num\u00e9rico).

    {\n  \"id\": \"pgto-001\",\n  \"tPag\": \"17\",\n  \"description\": null,\n  \"value\": 50.00,\n  \"additionalInfo\": null\n}\n

    Resposta \u2014 400 (pagamento duplicado)

    { \"code\": 400, \"message\": \"Pagamento j\u00e1 existente na venda!\" }\n
    " + }, + { + "location": "api/sale/#exemplos-de-integracao_9", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/sale/payment \\\n     -d '{\"id\":\"pgto-001\",\"tPag\":\"17\",\"value\":50.00}'\n
    final payment = await TefIP.instance.salePayment.post(\n  payment: SalePaymentModel(\n    id: 'pgto-001',\n    type: TefIPSalePaymentType.pix,\n    value: 50.00,\n  ),\n);\nprint(payment.id);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/payment', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ id: 'pgto-001', tPag: '17', value: 50.00 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/payment');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['id' => 'pgto-001', 'tPag' => '17', 'value' => 50.00]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/payment')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { id: 'pgto-001', tPag: '17', value: 50.00 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#patch-salepaymentpaymentid", + "title": "PATCH /sale/payment/{paymentId}", + "text": "

    Atualiza os dados de um pagamento j\u00e1 adicionado \u00e0 venda.

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o paymentId string Identificador do pagamento a atualizar

    Corpo igual ao de POST /sale/payment. O id no corpo \u00e9 ignorado \u2014 vem do par\u00e2metro de rota.

    Resposta \u2014 200

    Retorna o pagamento atualizado (com tPag num\u00e9rico).

    " + }, + { + "location": "api/sale/#exemplos-de-integracao_10", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X PATCH http://localhost:9050/sale/payment/pgto-001 \\\n     -d '{\"tPag\":\"03\",\"value\":50.00}'\n
    await TefIP.instance.salePayment.patch(\n  paymentId: 'pgto-001',\n  payment: SalePaymentModel(\n    type: TefIPSalePaymentType.credit,\n    value: 50.00,\n  ),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/payment/pgto-001', {\n  method: 'PATCH',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ tPag: '03', value: 50.00 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/payment/pgto-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['tPag' => '03', 'value' => 50.00]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/payment/pgto-001')\nreq = Net::HTTP::Patch.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { tPag: '03', value: 50.00 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#delete-salepaymentclear", + "title": "DELETE /sale/payment/clear", + "text": "

    Remove todos os pagamentos da venda ativa, preservando itens, descontos e acr\u00e9scimos.

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    " + }, + { + "location": "api/sale/#exemplos-de-integracao_11", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X DELETE http://localhost:9050/sale/payment/clear\n
    await TefIP.instance.salePayment.clear();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/payment/clear', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/payment/clear');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/payment/clear')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#delete-salepaymentpaymentid", + "title": "DELETE /sale/payment/{paymentId}", + "text": "

    Remove uma forma de pagamento do carrinho da venda ativa.

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o paymentId string Identificador do pagamento a remover

    Resposta \u2014 200

    Retorna o cupom completo (SaleCoupon, ver Forma das respostas).

    " + }, + { + "location": "api/sale/#exemplos-de-integracao_12", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X DELETE http://localhost:9050/sale/payment/pgto-001\n
    await TefIP.instance.salePayment.delete(paymentId: 'pgto-001');\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/payment/pgto-001', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/payment/pgto-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/payment/pgto-001')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#descontos-da-venda", + "title": "Descontos da venda", + "text": "

    Descontos s\u00e3o valores subtra\u00eddos do total da venda, independentes dos descontos por item. Cada desconto tem um id pr\u00f3prio.

    " + }, + { + "location": "api/sale/#post-salediscount", + "title": "POST /sale/discount", + "text": "

    Adiciona um desconto \u00e0 venda ativa.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"id\": \"desc-001\",\n  \"description\": \"Cupom 10%\",\n  \"value\": 5.00,\n  \"additionalInfo\": null\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o id string Sim Identificador \u00fanico do desconto description string N\u00e3o Descri\u00e7\u00e3o exibida no terminal value number Sim Valor do desconto em reais (armazenado em m\u00f3dulo) additionalInfo string N\u00e3o Informa\u00e7\u00e3o adicional

    Resposta \u2014 200

    Retorna o desconto criado (mesmo formato do corpo).

    Resposta \u2014 400 (desconto duplicado)

    { \"code\": 400, \"message\": \"Desconto j\u00e1 existente na venda!\" }\n
    " + }, + { + "location": "api/sale/#exemplos-de-integracao_13", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/sale/discount \\\n     -d '{\"id\":\"desc-001\",\"description\":\"Cupom 10%\",\"value\":5.00}'\n
    final discount = await TefIP.instance.saleDiscount.post(\n  discount: SaleDiscountModel(id: 'desc-001', description: 'Cupom 10%', value: 5.00),\n);\nprint(discount.id);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/discount', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ id: 'desc-001', description: 'Cupom 10%', value: 5.00 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/discount');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'id' => 'desc-001', 'description' => 'Cupom 10%', 'value' => 5.00,\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/discount')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { id: 'desc-001', description: 'Cupom 10%', value: 5.00 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#patch-salediscountdiscountid", + "title": "PATCH /sale/discount/{discountId}", + "text": "

    Atualiza um desconto existente. O id no corpo \u00e9 ignorado \u2014 vem do par\u00e2metro de rota. Retorna o desconto atualizado.

    cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X PATCH http://localhost:9050/sale/discount/desc-001 \\\n     -d '{\"value\":7.50}'\n
    await TefIP.instance.saleDiscount.patch(\n  discountId: 'desc-001',\n  discount: SaleDiscountModel(id: 'desc-001', value: 7.50),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/discount/desc-001', {\n  method: 'PATCH',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ value: 7.50 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/discount/desc-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['value' => 7.50]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/discount/desc-001')\nreq = Net::HTTP::Patch.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { value: 7.50 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#delete-salediscountdiscountid-delete-salediscountclear", + "title": "DELETE /sale/discount/{discountId} \u00b7 DELETE /sale/discount/clear", + "text": "

    DELETE /sale/discount/{discountId} remove um desconto; DELETE /sale/discount/clear remove todos. Ambos retornam o cupom completo (SaleCoupon, ver Forma das respostas).

    cURLDartJavaScriptPHPRuby
    curl -u admin:1234 -X DELETE http://localhost:9050/sale/discount/desc-001\ncurl -u admin:1234 -X DELETE http://localhost:9050/sale/discount/clear\n
    await TefIP.instance.saleDiscount.delete(discountId: 'desc-001');\nawait TefIP.instance.saleDiscount.clear();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nawait fetch('http://localhost:9050/sale/discount/desc-001', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/discount/desc-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/discount/desc-001')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#acrescimos-da-venda", + "title": "Acr\u00e9scimos da venda", + "text": "

    Acr\u00e9scimos s\u00e3o valores somados ao total da venda (ex.: taxa de servi\u00e7o). Sim\u00e9tricos aos descontos, cada um com id pr\u00f3prio.

    " + }, + { + "location": "api/sale/#post-saleaddition", + "title": "POST /sale/addition", + "text": "

    Adiciona um acr\u00e9scimo \u00e0 venda ativa.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"id\": \"acrs-001\",\n  \"description\": \"Taxa de servi\u00e7o 10%\",\n  \"value\": 4.50,\n  \"additionalInfo\": null\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o id string Sim Identificador \u00fanico do acr\u00e9scimo description string N\u00e3o Descri\u00e7\u00e3o exibida no terminal value number Sim Valor do acr\u00e9scimo em reais (armazenado em m\u00f3dulo) additionalInfo string N\u00e3o Informa\u00e7\u00e3o adicional

    Resposta \u2014 200

    Retorna o acr\u00e9scimo criado (mesmo formato do corpo).

    Resposta \u2014 400 (acr\u00e9scimo duplicado)

    { \"code\": 400, \"message\": \"Acr\u00e9scimo j\u00e1 existente na venda!\" }\n
    " + }, + { + "location": "api/sale/#exemplos-de-integracao_14", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/sale/addition \\\n     -d '{\"id\":\"acrs-001\",\"description\":\"Taxa de servi\u00e7o 10%\",\"value\":4.50}'\n
    final addition = await TefIP.instance.saleAddition.post(\n  addition: SaleAdditionModel(id: 'acrs-001', description: 'Taxa de servi\u00e7o 10%', value: 4.50),\n);\nprint(addition.id);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/addition', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ id: 'acrs-001', description: 'Taxa de servi\u00e7o 10%', value: 4.50 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/addition');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'id' => 'acrs-001', 'description' => 'Taxa de servi\u00e7o 10%', 'value' => 4.50,\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/addition')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { id: 'acrs-001', description: 'Taxa de servi\u00e7o 10%', value: 4.50 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#patch-saleadditionadditionid", + "title": "PATCH /sale/addition/{additionId}", + "text": "

    Atualiza um acr\u00e9scimo existente. O id no corpo \u00e9 ignorado \u2014 vem do par\u00e2metro de rota. Retorna o acr\u00e9scimo atualizado.

    cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X PATCH http://localhost:9050/sale/addition/acrs-001 \\\n     -d '{\"value\":6.00}'\n
    await TefIP.instance.saleAddition.patch(\n  additionId: 'acrs-001',\n  addition: SaleAdditionModel(id: 'acrs-001', value: 6.00),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/addition/acrs-001', {\n  method: 'PATCH',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ value: 6.00 }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/addition/acrs-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['value' => 6.00]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/addition/acrs-001')\nreq = Net::HTTP::Patch.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { value: 6.00 }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#delete-saleadditionadditionid-delete-saleadditionclear", + "title": "DELETE /sale/addition/{additionId} \u00b7 DELETE /sale/addition/clear", + "text": "

    DELETE /sale/addition/{additionId} remove um acr\u00e9scimo; DELETE /sale/addition/clear remove todos. Ambos retornam o cupom completo (SaleCoupon, ver Forma das respostas).

    cURLDartJavaScriptPHPRuby
    curl -u admin:1234 -X DELETE http://localhost:9050/sale/addition/acrs-001\ncurl -u admin:1234 -X DELETE http://localhost:9050/sale/addition/clear\n
    await TefIP.instance.saleAddition.delete(additionId: 'acrs-001');\nawait TefIP.instance.saleAddition.clear();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nawait fetch('http://localhost:9050/sale/addition/acrs-001', {\n  method: 'DELETE',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/addition/acrs-001');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/addition/acrs-001')\nreq = Net::HTTP::Delete.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#post-salefinalize", + "title": "POST /sale/finalize", + "text": "

    Finaliza a venda ativa. Todos os itens e pagamentos adicionados s\u00e3o consolidados.

    Corpo da requisi\u00e7\u00e3o (opcional)

    {\n  \"message\": \"Obrigado pela compra!\",\n  \"showMessage\": true,\n  \"showCloseButton\": true,\n  \"showResultScreen\": true,\n  \"buttonCloseText\": \"Fechar\",\n  \"messageInterval\": 3000\n}\n
    Campo Tipo Padr\u00e3o Descri\u00e7\u00e3o message string null Mensagem exibida ao finalizar showMessage bool true Exibe a mensagem de finaliza\u00e7\u00e3o showCloseButton bool true Exibe bot\u00e3o para fechar a tela showResultScreen bool true Exibe a tela de resultado da venda buttonCloseText string null Texto do bot\u00e3o fechar messageInterval int 3000 Dura\u00e7\u00e3o (ms) da mensagem exibida

    Resposta \u2014 200

    { \"message\": \"Venda finalizada com sucesso\" }\n
    " + }, + { + "location": "api/sale/#exemplos-de-integracao_15", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/sale/finalize \\\n     -d '{\"message\":\"Obrigado pela compra!\",\"showMessage\":true}'\n
    await TefIP.instance.saleFinalize.post(\n  params: SaleActionRequestModel(message: 'Obrigado pela compra!'),\n);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/finalize', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ message: 'Obrigado pela compra!', showMessage: true }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/finalize');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['message' => 'Obrigado pela compra!', 'showMessage' => true]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/finalize')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { message: 'Obrigado pela compra!', showMessage: true }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/sale/#post-salecancel", + "title": "POST /sale/cancel", + "text": "

    Cancela a venda ativa e limpa o carrinho.

    Corpo da requisi\u00e7\u00e3o (opcional)

    Mesmo formato de POST /sale/finalize.

    Resposta \u2014 200

    { \"message\": \"Venda cancelada com sucesso\" }\n
    " + }, + { + "location": "api/sale/#exemplos-de-integracao_16", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/sale/cancel\n
    await TefIP.instance.saleCancel.post();\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/sale/cancel', {\n  method: 'POST',\n  headers: { 'Authorization': 'Basic ' + btoa('admin:1234') },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/sale/cancel');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/sale/cancel')\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/status/", + "title": "Status", + "text": "

    Endpoints para monitorar a sa\u00fade do servidor TEF IP, consultar informa\u00e7\u00f5es do dispositivo e reiniciar o aplicativo remotamente. Estes endpoints s\u00e3o sempre seguros de chamar \u2014 respondem mesmo durante pagamentos em andamento.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    Dispon\u00edveis mesmo durante opera\u00e7\u00f5es

    GET /status, GET /info e POST /restart respondem normalmente mesmo quando h\u00e1 uma opera\u00e7\u00e3o em andamento (isBusy=true). Use-os livremente para monitorar o estado do servidor sem risco de 503.

    " + }, + { + "location": "api/status/#get-status", + "title": "GET /status", + "text": "

    Verifica se o servidor est\u00e1 no ar e retorna o tempo de atividade.

    Resposta

    {\n  \"status\": \"ok\",\n  \"uptimeSeconds\": 144,\n  \"startedAt\": \"2026-01-28T16:20:53.223883\"\n}\n
    Campo Tipo Descri\u00e7\u00e3o status string Sempre \"ok\" quando o servidor responde uptimeSeconds int Segundos desde a inicializa\u00e7\u00e3o do servidor startedAt string Data/hora de in\u00edcio em formato ISO 8601" + }, + { + "location": "api/status/#exemplos-de-integracao", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     http://localhost:9050/status\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal status = await TefIP.instance.status.get();\nprint(status.uptimeSeconds);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/status', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/status');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/status')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/status/#get-info", + "title": "GET /info", + "text": "

    Retorna informa\u00e7\u00f5es detalhadas sobre o aplicativo e o dispositivo, incluindo o estado atual do servidor.

    Resposta

    {\n  \"appName\": \"TEF IP\",\n  \"version\": \"1.2.0\",\n  \"build\": \"42\",\n  \"platform\": \"android\",\n  \"locale\": \"pt_BR\",\n  \"timeZone\": \"America/Sao_Paulo\",\n  \"mode\": \"production\",\n  \"isActive\": true,\n  \"isBusy\": false\n}\n
    Campo Tipo Descri\u00e7\u00e3o appName string Nome do aplicativo version string Vers\u00e3o sem\u00e2ntica build string N\u00famero de build platform string Plataforma do dispositivo (android, windows, etc.) locale string Locale configurado no dispositivo timeZone string Fuso hor\u00e1rio do dispositivo mode string Modo de opera\u00e7\u00e3o (production, emulator) isActive bool true quando o app est\u00e1 em primeiro plano isBusy bool true quando h\u00e1 uma opera\u00e7\u00e3o em andamento (pagamento, impress\u00e3o)

    Monitorando isBusy

    Use isBusy para saber se o terminal est\u00e1 livre antes de enviar uma nova opera\u00e7\u00e3o. Requisi\u00e7\u00f5es enviadas enquanto isBusy \u00e9 true ser\u00e3o rejeitadas com 503.

    Saiba mais

    Veja Comportamento \u2192 Servidor ocupado para entender como o servidor lida com opera\u00e7\u00f5es simult\u00e2neas.

    " + }, + { + "location": "api/status/#exemplos-de-integracao_1", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     http://localhost:9050/info\n
    final info = await TefIP.instance.info.get();\nprint('${info.appName} v${info.version} \u2014 isBusy: ${info.isBusy}');\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/info', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/info');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/info')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/status/#post-restart", + "title": "POST /restart", + "text": "

    Reinicia o aplicativo TEF IP remotamente. Dispon\u00edvel apenas em dispositivos m\u00f3veis (Android ou iOS).

    Somente dispositivos m\u00f3veis

    Em plataformas n\u00e3o-m\u00f3veis (Windows, emulador de desktop), este endpoint retorna 403.

    Resposta \u2014 200

    Mesma estrutura de GET /status, refletindo o estado ap\u00f3s o rein\u00edcio.

    {\n  \"status\": \"ok\",\n  \"uptimeSeconds\": 0,\n  \"startedAt\": \"2026-03-25T10:00:00.000000\"\n}\n

    Resposta \u2014 403

    {\n  \"code\": 403,\n  \"message\": \"Reinicializa\u00e7\u00e3o dispon\u00edvel apenas para dispositivos m\u00f3veis\"\n}\n
    " + }, + { + "location": "api/status/#exemplos-de-integracao_2", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/restart\n
    final result = await TefIP.instance.restart.post();\nprint(result.status);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/restart', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/restart');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/restart')\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/swagger/", + "title": "Swagger / OpenAPI", + "text": "

    O TEF IP exp\u00f5e uma interface Swagger UI interativa e o spec OpenAPI diretamente no terminal \u2014 sem necessidade de nenhuma ferramenta externa.

    Rotas p\u00fablicas

    Os endpoints /docs e /openapi.bundle.yaml n\u00e3o exigem autentica\u00e7\u00e3o e podem ser acessados diretamente no navegador.

    " + }, + { + "location": "api/swagger/#get-docs", + "title": "GET /docs", + "text": "

    Abre a interface Swagger UI no navegador. Permite explorar e testar todos os endpoints da API de forma interativa.

    O spec \u00e9 carregado automaticamente e os servidores dispon\u00edveis s\u00e3o detectados e listados em tempo real com base nas inst\u00e2ncias ativas do TEF IP na rede.

    Como acessar:

    Abra o navegador e acesse http://<ip-do-terminal>:9050/docs.

    " + }, + { + "location": "api/swagger/#get-openapibundleyaml", + "title": "GET /openapi.bundle.yaml", + "text": "

    Retorna o spec OpenAPI completo em formato YAML. O spec inclui a lista de servidores detectados dinamicamente, incluindo o status de cada inst\u00e2ncia (Online/Offline).

    Resposta \u2014 200

    openapi: 3.0.0\ninfo:\n  title: TEF IP API\n  version: 1.0.0\n# ...\nservers:\n  - url: http://192.168.1.100:9050\n    description: Online\n  - url: http://192.168.1.101:9050\n    description: Offline\n

    O arquivo pode ser importado em qualquer ferramenta compat\u00edvel com OpenAPI (Postman, Insomnia, etc.).

    " + }, + { + "location": "api/swagger/#como-importar-no-postman", + "title": "Como importar no Postman", + "text": "
    1. Abra o Postman e clique em Import.
    2. Selecione Link e cole: http://<ip-do-terminal>:9050/openapi.bundle.yaml
    3. Clique em Continue e confirme a importa\u00e7\u00e3o.
    " + }, + { + "location": "api/swagger/#como-importar-no-insomnia", + "title": "Como importar no Insomnia", + "text": "
    1. Abra o Insomnia e clique em Create \u2192 Import from URL.
    2. Cole: http://<ip-do-terminal>:9050/openapi.bundle.yaml
    3. Confirme a importa\u00e7\u00e3o.
    " + }, + { + "location": "api/transaction/", + "title": "Transa\u00e7\u00f5es", + "text": "

    Endpoints para processar pagamentos, consultar hist\u00f3rico e realizar estornos.

    Autentica\u00e7\u00e3o

    Todas as requisi\u00e7\u00f5es exigem Basic Auth. Use as credenciais configuradas no TEF IP (admin / senha definida na instala\u00e7\u00e3o).

    " + }, + { + "location": "api/transaction/#post-transaction", + "title": "POST /transaction", + "text": "

    Inicia um pagamento no terminal. O TEF IP aguarda o app estar em primeiro plano por at\u00e9 15 segundos antes de processar \u2014 se o app estiver minimizado, o endpoint retorna 503.

    App em segundo plano

    Se o TEF IP estiver minimizado, aguarda at\u00e9 15 s pelo retorno ao primeiro plano antes de processar \u2014 caso contr\u00e1rio retorna 503. Veja Comportamento \u2192 App em segundo plano.

    Corpo da requisi\u00e7\u00e3o

    {\n  \"tPag\": \"17\",\n  \"amount\": 50.00,\n  \"referenceId\": \"pedido-001\",\n  \"installments\": 1,\n  \"installmentType\": \"single\",\n  \"details\": {}\n}\n
    Campo Tipo Obrigat\u00f3rio Descri\u00e7\u00e3o tPag string Sim Tipo de pagamento (ver tabela abaixo) amount number Sim Valor da transa\u00e7\u00e3o referenceId string N\u00e3o Identificador externo para concilia\u00e7\u00e3o. Sem este campo, a transa\u00e7\u00e3o n\u00e3o pode ser estornada individualmente \u2014 aparece apenas na listagem geral. Use o n\u00famero do pedido ou UUID da venda. installments int N\u00e3o N\u00famero de parcelas (padr\u00e3o: 1) installmentType string N\u00e3o Modalidade de parcelamento (padr\u00e3o: \"single\") details object N\u00e3o Metadados adicionais da transa\u00e7\u00e3o

    referenceId \u00e9 necess\u00e1rio para estornos

    Sem referenceId, a transa\u00e7\u00e3o s\u00f3 aparece na listagem geral (GET /transaction) e n\u00e3o pode ser estornada individualmente. Defina-o sempre que a opera\u00e7\u00e3o puder precisar de estorno futuro.

    Valores de tPag

    Valor Descri\u00e7\u00e3o \"01\" Dinheiro \"03\" Cr\u00e9dito \"04\" D\u00e9bito \"05\" Cart\u00e3o-presente \"17\" PIX \"99\" Desconhecido

    Valores de installmentType

    Valor Descri\u00e7\u00e3o \"single\" Pagamento \u00e0 vista (padr\u00e3o) \"seller\" Parcelado pelo lojista (sem juros ao comprador) \"buyer\" Parcelado pelo comprador (juros ao comprador)

    Resposta \u2014 200

    {\n  \"nsu\": \"123456\",\n  \"cnpj\": \"05481336000137\",\n  \"cAut\": \"123456\",\n  \"txid\": null,\n  \"tBand\": \"01\",\n  \"tPag\": \"17\",\n  \"details\": {}\n}\n
    Campo Tipo Descri\u00e7\u00e3o nsu string N\u00famero sequencial \u00fanico gerado pelo adquirente cnpj string CNPJ do adquirente/emissor retornado pelo terminal cAut string C\u00f3digo de autoriza\u00e7\u00e3o \u2014 presente em cr\u00e9dito/d\u00e9bito; null em PIX txid string Identificador da transa\u00e7\u00e3o \u2014 presente apenas em PIX; null nos demais tipos tBand string Bandeira do cart\u00e3o retornada pelo adquirente tPag string C\u00f3digo do tipo de pagamento (ver tabela de tPag) details object Dados adicionais retornados pelo adquirente

    Resposta \u2014 503 (app em segundo plano)

    {\n  \"code\": 503,\n  \"message\": \"Aplicativo em segundo plano. Abra o app para concluir o pagamento.\"\n}\n
    " + }, + { + "location": "api/transaction/#exemplos-de-integracao", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -H \"Content-Type: application/json\" \\\n     -X POST http://localhost:9050/transaction \\\n     -d '{\"tPag\":\"17\",\"amount\":50.00,\"referenceId\":\"pedido-001\"}'\n
    // pub.dev/packages/dart_tefip \u2014 configure uma vez; demais exemplos nesta p\u00e1gina omitem esta etapa\nTefIP.baseUrl = 'http://localhost:9050';\nTefIP.username = 'admin';\nTefIP.password = '1234';\nfinal result = await TefIP.instance.transaction.post(\n  transactionRequest: TransactionRequestModel(\n    type: TefIPTransactionType.pix,\n    amount: 50.00,\n    referenceId: 'pedido-001',\n  ),\n);\nprint(result.nsu);          // NSU do adquirente\nprint(result.txid);         // preenchido em PIX\nprint(result.cAut);         // preenchido em cr\u00e9dito/d\u00e9bito\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/transaction', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ tPag: '17', amount: 50.00, referenceId: 'pedido-001' }),\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/transaction');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([\n    'tPag' => '17',\n    'amount' => 50.00,\n    'referenceId' => 'pedido-001',\n]));\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/transaction')\nreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')\nreq.basic_auth('admin', '1234')\nreq.body = { tPag: '17', amount: 50.00, referenceId: 'pedido-001' }.to_json\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/transaction/#get-transaction", + "title": "GET /transaction", + "text": "

    Lista todas as transa\u00e7\u00f5es registradas no terminal.

    Resposta \u2014 200

    Array de transa\u00e7\u00f5es, cada uma com a mesma estrutura do retorno de POST /transaction.

    [\n  {\n    \"nsu\": \"123456\",\n    \"cnpj\": \"05481336000137\",\n    \"cAut\": \"123456\",\n    \"txid\": null,\n    \"tBand\": \"01\",\n    \"tPag\": \"17\",\n    \"details\": {}\n  }\n]\n
    " + }, + { + "location": "api/transaction/#exemplos-de-integracao_1", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     http://localhost:9050/transaction\n
    final transactions = await TefIP.instance.transaction.getAll();\nfor (final t in transactions) {\n  print(t.nsu);\n}\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/transaction', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$ch = curl_init('http://localhost:9050/transaction');\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nuri = URI('http://localhost:9050/transaction')\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/transaction/#get-transactionreferenceid", + "title": "GET /transaction/{referenceId}", + "text": "

    Busca uma transa\u00e7\u00e3o espec\u00edfica pelo identificador externo informado no momento do pagamento.

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o referenceId string Identificador externo da transa\u00e7\u00e3o

    Resposta \u2014 200

    {\n  \"nsu\": \"123456\",\n  \"cnpj\": \"05481336000137\",\n  \"cAut\": \"123456\",\n  \"txid\": null,\n  \"tBand\": \"01\",\n  \"tPag\": \"17\",\n  \"details\": {}\n}\n
    " + }, + { + "location": "api/transaction/#exemplos-de-integracao_2", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     http://localhost:9050/transaction/pedido-001\n
    final transaction = await TefIP.instance.transaction.get(referenceId: 'pedido-001');\nprint(transaction.nsu);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/transaction/pedido-001', {\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$referenceId = 'pedido-001';\n$ch = curl_init(\"http://localhost:9050/transaction/{$referenceId}\");\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nreference_id = 'pedido-001'\nuri = URI(\"http://localhost:9050/transaction/#{reference_id}\")\nreq = Net::HTTP::Get.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "api/transaction/#post-transactionreferenceidreversal", + "title": "POST /transaction/{referenceId}/reversal", + "text": "

    Realiza o estorno de uma transa\u00e7\u00e3o pelo seu referenceId. Assim como o pagamento, aguarda o app estar em primeiro plano por at\u00e9 15 segundos.

    Par\u00e2metros de rota

    Par\u00e2metro Tipo Descri\u00e7\u00e3o referenceId string Identificador externo da transa\u00e7\u00e3o a estornar

    N\u00e3o h\u00e1 corpo na requisi\u00e7\u00e3o.

    Resposta \u2014 200

    Mesma estrutura de POST /transaction.

    {\n  \"nsu\": \"123456\",\n  \"cnpj\": \"05481336000137\",\n  \"cAut\": \"123456\",\n  \"txid\": null,\n  \"tBand\": \"01\",\n  \"tPag\": \"17\",\n  \"details\": {}\n}\n

    Resposta \u2014 503 (app em segundo plano)

    {\n  \"code\": 503,\n  \"message\": \"Aplicativo em segundo plano. Abra o app para concluir o estorno.\"\n}\n
    " + }, + { + "location": "api/transaction/#exemplos-de-integracao_3", + "title": "Exemplos de integra\u00e7\u00e3o", + "text": "cURLDartJavaScriptPHPRuby
    curl -u admin:1234 \\\n     -X POST http://localhost:9050/transaction/pedido-001/reversal\n
    final result = await TefIP.instance.reversal.post(referenceId: 'pedido-001');\nprint(result.nsu);\n
    // TODO: pacote JavaScript ainda n\u00e3o criado \u2014 usando fetch diretamente\nconst res = await fetch('http://localhost:9050/transaction/pedido-001/reversal', {\n  method: 'POST',\n  headers: {\n    'Authorization': 'Basic ' + btoa('admin:1234'),\n  },\n});\nconst data = await res.json();\n
    <?php\n// TODO: pacote PHP ainda n\u00e3o criado \u2014 usando curl diretamente\n$referenceId = 'pedido-001';\n$ch = curl_init(\"http://localhost:9050/transaction/{$referenceId}/reversal\");\ncurl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$response = json_decode(curl_exec($ch), true);\ncurl_close($ch);\n
    # TODO: pacote Ruby ainda n\u00e3o criado \u2014 usando Net::HTTP diretamente\nrequire 'net/http'\nrequire 'json'\n\nreference_id = 'pedido-001'\nuri = URI(\"http://localhost:9050/transaction/#{reference_id}/reversal\")\nreq = Net::HTTP::Post.new(uri)\nreq.basic_auth('admin', '1234')\nres = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }\ndata = JSON.parse(res.body)\n
    " + }, + { + "location": "suporte/resolucao-de-problemas/", + "title": "Resolu\u00e7\u00e3o de Problemas", + "text": "

    Use este guia para resolver as situa\u00e7\u00f5es mais comuns encontradas durante a instala\u00e7\u00e3o ou opera\u00e7\u00e3o do TEF IP no dia-a-dia.

    " + }, + { + "location": "suporte/resolucao-de-problemas/#checklist-de-conectividade", + "title": "Checklist de Conectividade", + "text": "

    Se o PDV n\u00e3o conseguir se comunicar com o TEF IP, verifique:

    1. Rede: O terminal de pagamento e o computador do PDV est\u00e3o na mesma rede Wi-Fi/CABO?
    2. IP: O IP configurado no seu sistema PDV \u00e9 o mesmo que aparece na tela do app TEF IP?
    3. Basic Auth: O usu\u00e1rio e a senha configurados no seu sistema est\u00e3o corretos?
    4. Firewall: Se estiver usando Windows, a porta 9050 est\u00e1 aberta para conex\u00f5es de entrada?
    " + }, + { + "location": "suporte/resolucao-de-problemas/#mensagens-de-erro-no-terminal", + "title": "Mensagens de Erro no Terminal", + "text": "" + }, + { + "location": "suporte/resolucao-de-problemas/#terminal-busy-ocupado", + "title": "\"Terminal Busy\" / \"Ocupado\"", + "text": "" + }, + { + "location": "suporte/resolucao-de-problemas/#app-em-segundo-plano", + "title": "\"App em Segundo Plano\"", + "text": "" + }, + { + "location": "suporte/resolucao-de-problemas/#coletando-evidencias-com-logs", + "title": "Coletando evid\u00eancias com logs", + "text": "

    Quando o comportamento n\u00e3o estiver claro, use os endpoints de logs para capturar evid\u00eancias antes de reiniciar o aplicativo:

    1. GET /logs para consultar erros recentes com filtros por n\u00edvel, origem e texto.
    2. GET /logs/stream para acompanhar eventos em tempo real enquanto reproduz o problema.
    3. GET /logs/zip/download para anexar os registros a um chamado de suporte.

    Veja os exemplos completos em Logs.

    " + }, + { + "location": "suporte/resolucao-de-problemas/#como-usar-o-restart", + "title": "Como usar o /restart", + "text": "

    O endpoint POST /restart \u00e9 uma ferramenta poderosa. Ele for\u00e7a a reinicializa\u00e7\u00e3o dos servi\u00e7os internos do servidor sem precisar fechar o app manualmente.

    Use quando: * O terminal n\u00e3o responder a novos comandos de venda mesmo estando ocioso. * Houver erros persistentes de comunica\u00e7\u00e3o com a adquirente (Stone/Rede/Getnet). * Voc\u00ea alterar configura\u00e7\u00f5es cr\u00edticas de rede no app.

    " + }, + { + "location": "suporte/versoes/", + "title": "Vers\u00f5es e Requisitos", + "text": "

    O TEF IP \u00e9 distribu\u00eddo em vers\u00f5es espec\u00edficas para cada adquirente. Cada vers\u00e3o \u00e9 otimizada para o hardware do adquirente correspondente. Escolher a vers\u00e3o correta \u00e9 essencial para que a integra\u00e7\u00e3o com o terminal funcione.

    " + }, + { + "location": "suporte/versoes/#versoes-disponiveis", + "title": "Vers\u00f5es Dispon\u00edveis", + "text": "Adquirente Hardware Alvo Depend\u00eancias Externas Stone SmartPOS App \"Stone SDK\" Rede SmartPOS App \"Pagamento Rede\" Getnet SmartPOS App \"Global Payments\" Emulador Windows / Android Nenhuma (perfeito para testes)" + }, + { + "location": "suporte/versoes/#requisitos-de-instalacao", + "title": "Requisitos de Instala\u00e7\u00e3o", + "text": "" + }, + { + "location": "suporte/versoes/#no-terminal-adquirente-smartpos", + "title": "No Terminal Adquirente (SmartPOS)", + "text": "
    1. Conectividade: O terminal deve estar na mesma rede Wi-Fi que o PDV.
    2. IP Est\u00e1tico: Recomenda-se configurar um IP fixo para o terminal no roteador para evitar que o PDV perca a conex\u00e3o.
    3. Apps de Apoio: Garanta que as depend\u00eancias externas listadas na tabela acima estejam instaladas e atualizadas.
    4. Permiss\u00f5es: Ao abrir o TEF IP pela primeira vez, aceite todas as permiss\u00f5es de rede, telefone e armazenamento.
    " + }, + { + "location": "suporte/versoes/#no-windows-emulador", + "title": "No Windows (Emulador)", + "text": "
    1. Porta 9050: Certifique-se de que a porta 9050 est\u00e1 aberta no Firewall do Windows para conex\u00f5es de entrada.
    2. Basic Auth: Configure o usu\u00e1rio e senha desejados no arquivo de configura\u00e7\u00f5es do app.
    3. Visual C++ Redistributable: Pode ser necess\u00e1rio para a execu\u00e7\u00e3o do app em algumas vers\u00f5es do Windows.

    Valida\u00e7\u00e3o p\u00f3s-instala\u00e7\u00e3o

    Depois da instala\u00e7\u00e3o, confirme o ambiente com GET /status em http://localhost:9050/status. Se a API responder, a porta, o servi\u00e7o e a autentica\u00e7\u00e3o b\u00e1sica j\u00e1 estar\u00e3o operacionais.

    " + }, + { + "location": "suporte/versoes/#como-identificar-a-versao", + "title": "Como Identificar a Vers\u00e3o", + "text": "

    Ao abrir o aplicativo TEF IP, a vers\u00e3o e o adquirente configurado geralmente constam na tela \"Sobre\" ou no rodap\u00e9 da tela inicial. Certifique-se de que o logotipo do adquirente no app corresponde ao terminal f\u00edsico que voc\u00ea possui.

    " + } + ] +} \ No newline at end of file diff --git a/site/sitemap.xml b/site/sitemap.xml index dd81934..f70f5fe 100644 --- a/site/sitemap.xml +++ b/site/sitemap.xml @@ -81,7 +81,7 @@ 2026-06-18 - https://tefip.github.io/tefip_docs/suporte/versoes-requisitos/ + https://tefip.github.io/tefip_docs/suporte/versoes/ 2026-06-18 \ No newline at end of file diff --git a/site/suporte/resolucao-de-problemas/index.html b/site/suporte/resolucao-de-problemas/index.html index 3257132..c5a15e2 100644 --- a/site/suporte/resolucao-de-problemas/index.html +++ b/site/suporte/resolucao-de-problemas/index.html @@ -1,1501 +1,1551 @@ - - - - - - - - - - - - - - - - - - - - - - - - Resolução de Problemas - TEF IP Docs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - Pular para conteúdo - - -
    -
    - -
    - - - - -
    - - -
    - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  • - - - - - - - - - -
  • -
    -
    - - - -
    - -
    -
    - - - -
    - -
    - - - - - -

    Resolução de Problemas

    -

    Use este guia para resolver as situações mais comuns encontradas durante a instalação ou operação do TEF IP no dia-a-dia.

    -
    -

    Checklist de Conectividade

    -

    Se o PDV não conseguir se comunicar com o TEF IP, verifique:

    -
      -
    1. Rede: O terminal de pagamento e o computador do PDV estão na mesma rede Wi-Fi/CABO?
    2. -
    3. IP: O IP configurado no seu sistema PDV é o mesmo que aparece na tela do app TEF IP?
    4. -
    5. Basic Auth: O usuário e a senha configurados no seu sistema estão corretos?
    6. -
    7. Firewall: Se estiver usando Windows, a porta 9050 está aberta para conexões de entrada?
    8. -
    -
    -

    Mensagens de Erro no Terminal

    -

    "Terminal Busy" / "Ocupado"

    -
      -
    • Causa: Outra operação (pagamento ou impressão) está em andamento.
    • -
    • Solução: Aguarde o término da operação atual. Se o terminal parecer travado, use POST /restart ou reinicie o app manualmente.
    • -
    -

    "App em Segundo Plano"

    -
      -
    • Causa: O operador minimizou o app TEF IP.
    • -
    • Solução: Abra o app TEF IP no terminal. Verifique se as notificações estão habilitadas para o app.
    • -
    -
    -

    Coletando evidências com logs

    -

    Quando o comportamento não estiver claro, use os endpoints de logs para capturar evidências antes de reiniciar o aplicativo:

    -
      -
    1. GET /logs para consultar erros recentes com filtros por nível, origem e texto.
    2. -
    3. GET /logs/stream para acompanhar eventos em tempo real enquanto reproduz o problema.
    4. -
    5. GET /logs/zip/download para anexar os registros a um chamado de suporte.
    6. -
    -

    Veja os exemplos completos em Logs.

    -
    -

    Como usar o /restart

    -

    O endpoint POST /restart é uma ferramenta poderosa. Ele força a reinicialização dos serviços internos do servidor sem precisar fechar o app manualmente.

    -

    Use quando: -* O terminal não responder a novos comandos de venda mesmo estando ocioso. -* Houver erros persistentes de comunicação com a adquirente (Stone/Rede/Getnet). -* Você alterar configurações críticas de rede no app.

    - - - - - - - - - - - - - -
    -
    - - - - -
    - - - - - - -
    -
    -
    - - - - - - - - - - - - - - + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + + + + + +
    + +
    + + + + + +

    Resolução de Problemas

    +

    Use este guia para resolver as situações mais comuns encontradas durante a instalação ou operação do TEF + IP no dia-a-dia.

    +
    +

    Checklist de Conectividade

    +

    Se o PDV não conseguir se comunicar com o TEF IP, verifique:

    +
      +
    1. Rede: O terminal de pagamento e o computador do PDV estão na mesma rede Wi-Fi/CABO? +
    2. +
    3. IP: O IP configurado no seu sistema PDV é o mesmo que aparece na tela do app TEF IP? +
    4. +
    5. Basic Auth: O usuário e a senha configurados no seu sistema estão corretos?
    6. +
    7. Firewall: Se estiver usando Windows, a porta 9050 está aberta para + conexões de entrada?
    8. +
    +
    +

    Mensagens de Erro no Terminal

    +

    "Terminal Busy" / "Ocupado"

    +
      +
    • Causa: Outra operação (pagamento ou impressão) está em andamento.
    • +
    • Solução: Aguarde o término da operação atual. Se o terminal parecer travado, use + POST /restart ou reinicie o app manualmente. +
    • +
    +

    "App em Segundo Plano"

    +
      +
    • Causa: O operador minimizou o app TEF IP.
    • +
    • Solução: Abra o app TEF IP no terminal. Verifique se as notificações estão + habilitadas para o app.
    • +
    +
    +

    Coletando evidências com logs

    +

    Quando o comportamento não estiver claro, use os endpoints de logs para capturar evidências antes de + reiniciar o aplicativo:

    +
      +
    1. GET /logs para consultar erros recentes com filtros por nível, origem e texto.
    2. +
    3. GET /logs/stream para acompanhar eventos em tempo real enquanto reproduz o problema.
    4. +
    5. GET /logs/zip/download para anexar os registros a um chamado de suporte.
    6. +
    +

    Veja os exemplos completos em Logs.

    +
    +

    Como usar o /restart

    +

    O endpoint POST /restart é uma ferramenta poderosa. Ele força a reinicialização dos serviços + internos do servidor sem precisar fechar o app manualmente.

    +

    Use quando: + * O terminal não responder a novos comandos de venda mesmo estando ocioso. + * Houver erros persistentes de comunicação com a adquirente (Stone/Rede/Getnet). + * Você alterar configurações críticas de rede no app.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + +
    + + + + +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/suporte/versoes-requisitos/index.html b/site/suporte/versoes-requisitos/index.html index 0067946..defb325 100644 --- a/site/suporte/versoes-requisitos/index.html +++ b/site/suporte/versoes-requisitos/index.html @@ -1,1499 +1,1553 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - Versões e Requisitos - TEF IP Docs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - Pular para conteúdo - - -
    -
    - -
    - - - - -
    - - -
    - -
    - - - - - - - - - -
    -
    - - - -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  • - - - - - - - - - -
  • -
    -
    - - - -
    -
    -
    - - -
    - - - -
  • - - - - Como Identificar a Versão - - - - -
  • - - - - -
    -
    -
    - - - -
    - -
    - - - - - -

    Versões e Requisitos

    -

    O TEF IP é distribuído em versões específicas para cada adquirente. Cada versão é otimizada para o hardware do adquirente correspondente. Escolher a versão correta é essencial para que a integração com o terminal funcione.

    -
    -

    Versões Disponíveis

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    AdquirenteHardware AlvoDependências Externas
    StoneSmartPOSApp "Stone SDK"
    RedeSmartPOSApp "Pagamento Rede"
    GetnetSmartPOSApp "Global Payments"
    EmuladorWindows / AndroidNenhuma (perfeito para testes)
    -
    -

    Requisitos de Instalação

    -

    No Terminal Adquirente (SmartPOS)

    -
      -
    1. Conectividade: O terminal deve estar na mesma rede Wi-Fi que o PDV.
    2. -
    3. IP Estático: Recomenda-se configurar um IP fixo para o terminal no roteador para evitar que o PDV perca a conexão.
    4. -
    5. Apps de Apoio: Garanta que as dependências externas listadas na tabela acima estejam instaladas e atualizadas.
    6. -
    7. Permissões: Ao abrir o TEF IP pela primeira vez, aceite todas as permissões de rede, telefone e armazenamento.
    8. -
    -

    No Windows (Emulador)

    -
      -
    1. Porta 9050: Certifique-se de que a porta 9050 está aberta no Firewall do Windows para conexões de entrada.
    2. -
    3. Basic Auth: Configure o usuário e senha desejados no arquivo de configurações do app.
    4. -
    5. Visual C++ Redistributable: Pode ser necessário para a execução do app em algumas versões do Windows.
    6. -
    -
    -

    Validação pós-instalação

    -

    Depois da instalação, confirme o ambiente com GET /status em http://localhost:9050/status. Se a API responder, a porta, o serviço e a autenticação básica já estarão operacionais.

    -
    -
    -

    Como Identificar a Versão

    -

    Ao abrir o aplicativo TEF IP, a versão e o adquirente configurado geralmente constam na tela "Sobre" ou no rodapé da tela inicial. Certifique-se de que o logotipo do adquirente no app corresponde ao terminal físico que você possui.

    - - - - - - - - - - - - - -
    -
    - - - - -
    - - - - - - -
    -
    -
    - - - - - - - - - - - - - - + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + + + + + +
    + +
    + + + + + +

    Versões

    +

    O TEF IP é distribuído em versões específicas para cada adquirente. Cada versão é otimizada para o + hardware do adquirente correspondente. Escolher a versão correta é essencial para que a integração com o + terminal funcione.

    +
    +

    Versões Disponíveis

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AdquirenteHardware AlvoDependências Externas
    StoneSmartPOSApp "Stone SDK"
    RedeSmartPOSApp "Pagamento Rede"
    GetnetSmartPOSApp "Global Payments"
    EmuladorWindows / AndroidNenhuma (perfeito para testes)
    +
    +

    Requisitos de Instalação

    +

    No Terminal Adquirente (SmartPOS)

    +
      +
    1. Conectividade: O terminal deve estar na mesma rede Wi-Fi que o PDV.
    2. +
    3. IP Estático: Recomenda-se configurar um IP fixo para o terminal no roteador para + evitar que o PDV perca a conexão.
    4. +
    5. Apps de Apoio: Garanta que as dependências externas listadas na tabela acima estejam + instaladas e atualizadas.
    6. +
    7. Permissões: Ao abrir o TEF IP pela primeira vez, aceite todas as permissões de rede, + telefone e armazenamento.
    8. +
    +

    No Windows (Emulador)

    +
      +
    1. Porta 9050: Certifique-se de que a porta 9050 está aberta no Firewall do + Windows para conexões de entrada.
    2. +
    3. Basic Auth: Configure o usuário e senha desejados no arquivo de configurações do app. +
    4. +
    5. Visual C++ Redistributable: Pode ser necessário para a execução do app em algumas + versões do Windows.
    6. +
    +
    +

    Validação pós-instalação

    +

    Depois da instalação, confirme o ambiente com GET /status em + http://localhost:9050/status. Se a API responder, a porta, o serviço e a autenticação + básica já estarão operacionais. +

    +
    +
    +

    Como Identificar a Versão

    +

    Ao abrir o aplicativo TEF IP, a versão e o adquirente configurado geralmente constam na tela "Sobre" ou + no rodapé da tela inicial. Certifique-se de que o logotipo do adquirente no app corresponde ao terminal + físico que você possui.

    + + + + + + + + + + + + + +
    +
    + + + + + +
    + +
    + + + + +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file