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.
| Header | Valor |
|---|---|
Content-Type |
application/octet-stream |
Resposta — 200
Resposta — 400 (nenhuma imagem enviada)
Resposta — 500 (erro na impressão)
Exemplos de integração
// pub.dev/packages/dart_tefip — configure uma vez; demais exemplos nesta página omitem esta etapa
import 'dart:io';
TefIP.baseUrl = 'http://localhost:9050';
TefIP.username = 'admin';
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
const imageBytes = await fetch('/comprovante.png').then(r => r.arrayBuffer());
const res = await fetch('http://localhost:9050/print/image', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('admin:1234'),
'Content-Type': 'application/octet-stream',
},
body: imageBytes,
});
const data = await res.json();
<?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');
curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/octet-stream']);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $imageData);
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
require 'net/http'
require 'json'
image_data = File.binread('comprovante.png')
uri = URI('http://localhost:9050/print/image')
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/octet-stream')
req.basic_auth('admin', '1234')
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
[
{ "text": { "value": "COMPROVANTE", "size": 20, "bold": true, "align": "center" } },
{ "line": { "divider": true } },
{ "text": { "value": "Produto: Coca-Cola", "size": 14, "bold": false, "align": "left" } },
{ "text": { "value": "Valor: R$ 5,00", "size": 14, "bold": false, "align": "left" } },
{ "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:
| Tipo | Exemplo |
|---|---|
| Texto | { "text": { "value": "...", "size": 16, "bold": false, "align": "left" } } |
| Divisor | { "line": { "divider": true } } |
Resposta — 200
Resposta — 400 (nenhum conteúdo enviado)
Exemplos de integração
// TODO: pacote JavaScript ainda não criado — usando fetch diretamente
const res = await fetch('http://localhost:9050/print/text', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('admin:1234'),
'Content-Type': 'application/json',
},
body: JSON.stringify([
{ text: { value: 'COMPROVANTE', size: 20, bold: true, align: 'center' } },
{ line: { divider: true } },
{ text: { value: 'Obrigado!', size: 14, bold: false, align: 'center' } },
]),
});
const data = await res.json();
<?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');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
['text' => ['value' => 'COMPROVANTE', 'size' => 20, 'bold' => true, 'align' => 'center']],
['line' => ['divider' => true]],
['text' => ['value' => 'Obrigado!', 'size' => 14, 'bold' => false, 'align' => 'center']],
]));
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
require 'net/http'
require 'json'
uri = URI('http://localhost:9050/print/text')
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
req.basic_auth('admin', '1234')
req.body = [
{ text: { value: 'COMPROVANTE', size: 20, bold: true, align: 'center' } },
{ line: { divider: true } },
{ text: { value: 'Obrigado!', size: 14, bold: false, align: 'center' } },
].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.
| Header | Valor |
|---|---|
Content-Type |
text/xml |
<?xml version="1.0" encoding="UTF-8"?>
<nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00">
...
</nfeProc>
Resposta — 200
Resposta — 400 (nenhum XML enviado)
Resposta — 500 (erro na impressão)
Exemplos de integração
// 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',
headers: {
'Authorization': 'Basic ' + btoa('admin:1234'),
'Content-Type': 'text/xml',
},
body: xml,
});
const data = await res.json();
<?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');
curl_setopt($ch, CURLOPT_USERPWD, 'admin:1234');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: text/xml']);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
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
require 'net/http'
require 'json'
xml = File.read('nota-fiscal.xml')
uri = URI('http://localhost:9050/print/xml')
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'text/xml')
req.basic_auth('admin', '1234')
req.body = xml
res = Net::HTTP.start(uri.hostname, uri.port) { |h| h.request(req) }
data = JSON.parse(res.body)