Guia 11 de 11
Integrar com Bling, Tiny, n8n, Zapier, Make e WooCommerce
Conecte o ERP uma vez e cada nota autorizada vira DANFE em PDF sem ninguém baixar XML. Para o resto, as ferramentas de automação chamam a mesma API que você já conhece.
O que você vai construir
Uma conexão com o Bling ou o Tiny que gera o DANFE (A4 ou 10×15) de cada nota autorizada e avisa o seu sistema pelo evento integracao.documentos, e um pedido HTTP pronto para usar no n8n, Zapier, Make ou num plugin WooCommerce.
Antes de começar
- Uma conta no Convertajá (as integrações com ERP ficam em Minha conta → Integrações).
- Bling: plano com acesso à API v3. Tiny: o token da API v2 (Configurações → Token API).
- Para n8n, Zapier, Make e WooCommerce: uma chave de API em
CONVERTAJA_KEY(veja Primeiros passos).
Qual integração usar
| Integração | Como liga | Situação |
|---|---|---|
| Bling | OAuth (API v3) + webhook de notas fiscais | Beta, em Minha conta |
| Tiny (Olist) | Token da API v2 + webhook de notas fiscais | Beta, em Minha conta |
| n8n | Nó da comunidade n8n-nodes-convertaja ou nó HTTP Request | Instalação manual; loja em breve |
| Zapier | App por convite ou Webhooks by Zapier | Diretório em breve |
| Make | App personalizado ou módulo HTTP | Lista pública em breve |
| WooCommerce | Plugin WordPress (.zip) | Diretório em breve |
Passo 1: Conecte o Bling ou o Tiny
- Bling: clique em Conectar ao Bling e autorize. Enquanto o app do Convertajá não está na Central de Extensões, use o seu próprio app do Bling: crie o app na área de desenvolvedor do Bling com o link de redirecionamento
https://convertaja.com.br/integracoes/bling/callback, cole o Client ID e o Client Secret e clique em Conectar. - Tiny: cole o token da API e salve. Conferimos o token na hora.
Credenciais e tokens ficam guardados criptografados (AES-256-GCM) e nunca voltam para o navegador.
Passo 2: Cadastre o webhook no ERP
A tela mostra um endereço secreto, único da sua conta:
https://convertaja.com.br/integracoes/bling/webhook/whk_… (Bling: recurso Notas fiscais)
https://convertaja.com.br/integracoes/tiny/webhook/whk_… (Tiny: webhooks de notas fiscais)
Cada aviso é conferido (Bling: assinatura X-Bling-Signature-256 com o client secret; Tiny: o token da URL), avisos repetidos são ignorados e respondemos 200 na hora. Depois buscamos o XML da nota na API do ERP e geramos o DANFE. Os eventos aparecem em Eventos recentes.
Atenção Quem tiver o endereço pode mandar avisos para a sua conta. Se ele vazar, clique em Gerar outro e troque no ERP.
Passo 3: Receba os PDFs por e-mail ou no seu sistema
Escolha o que gerar (DANFE A4, DANFE simplificado 10×15) e para onde mandar. Com um webhook do seu sistema, enviamos o evento integracao.documentos, assinado com o mesmo segredo e o mesmo cabeçalho X-Convertaja-Signature dos webhooks da API:
{
"id": "evt_5c1e0a9b2f7d4e6a8c3b",
"type": "integracao.documentos",
"created_at": "2026-10-17T14:02:11.480Z",
"data": {
"provider": "bling",
"event_id": 42,
"nota_id": "9001",
"numero": "4521",
"chave": null,
"files": [
{
"name": "NF-e 4521 - DISTRIBUIDORA PAULISTA DE FERRAGENS E MA.pdf",
"size": 6291,
"url": "https://convertaja.com.br/integracoes/arquivos/42/…/NF-e%204521%20-%20DISTRIBUIDORA%20PAULISTA%20DE%20FERRAGENS%20E%20MA.pdf"
}
],
"expires_at": "2026-10-24T14:02:11.480Z"
}
}Se o XML não puder ser baixado (nota sem XML, token revogado), chega integracao.falhou com data.error. Os links dos PDFs valem por 7 dias. Receptor completo:
// integracao.mjs: recebe o aviso "integracao.documentos" (DANFE gerado a partir do Bling ou do Tiny) e baixa os PDFs
// npm install express; node integracao.mjs
import crypto from 'node:crypto';
import { writeFile } from 'node:fs/promises';
import express from 'express';
const SEGREDO = process.env.CONVERTAJA_WEBHOOK_SECRET; // whsec_…, em Minha conta → API (o mesmo dos webhooks da API)
function assinaturaValida(corpoCru, cabecalho, segredo, toleranciaSeg = 300) {
const partes = Object.fromEntries(String(cabecalho || '').split(',').map((p) => p.split('=')));
const t = Number(partes.t);
if (!t || !partes.v1 || Math.abs(Date.now() / 1000 - t) > toleranciaSeg) return false;
const esperado = crypto.createHmac('sha256', segredo).update(`${t}.${corpoCru}`).digest('hex');
const a = Buffer.from(esperado);
const b = Buffer.from(String(partes.v1));
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
const app = express();
app.post('/webhooks/convertaja', express.raw({ type: 'application/json' }), (req, res) => {
const corpo = req.body.toString('utf8');
if (!assinaturaValida(corpo, req.get('X-Convertaja-Signature'), SEGREDO)) return res.sendStatus(400);
const evento = JSON.parse(corpo);
res.sendStatus(200);
if (evento.type === 'integracao.documentos') {
// data: { provider: "bling" | "tiny", nota_id, numero, chave, files: [{ name, size, url }], expires_at }
for (const f of evento.data.files) {
fetch(f.url).then((r) => r.arrayBuffer()).then((buf) => writeFile(f.name, Buffer.from(buf))).catch(console.error);
}
} else if (evento.type === 'integracao.falhou') {
console.error(`DANFE da nota ${evento.data.nota_id} (${evento.data.provider}) falhou: ${evento.data.error}`);
}
});
app.listen(8080);# integracao.py: recebe "integracao.documentos" (DANFE gerado a partir do Bling ou do Tiny) e baixa os PDFs
# pip install flask requests; python integracao.py
import hashlib
import hmac
import os
import time
import requests
from flask import Flask, abort, request
SEGREDO = os.environ["CONVERTAJA_WEBHOOK_SECRET"] # whsec_…, em Minha conta → API
def assinatura_valida(corpo_cru: bytes, cabecalho: str, segredo: str, tolerancia: int = 300) -> bool:
try:
partes = dict(p.split("=", 1) for p in (cabecalho or "").split(","))
t = int(partes.get("t", "0"))
except ValueError:
return False
if not t or not partes.get("v1") or abs(time.time() - t) > tolerancia:
return False
esperado = hmac.new(segredo.encode(), f"{t}.".encode() + corpo_cru, hashlib.sha256).hexdigest()
return hmac.compare_digest(esperado, partes["v1"])
app = Flask(__name__)
@app.post("/webhooks/convertaja")
def webhook():
corpo = request.get_data()
if not assinatura_valida(corpo, request.headers.get("X-Convertaja-Signature", ""), SEGREDO):
abort(400)
evento = request.get_json()
if evento["type"] == "integracao.documentos":
for f in evento["data"]["files"]: # links válidos por 7 dias
with open(f["name"], "wb") as out:
out.write(requests.get(f["url"], timeout=60).content)
elif evento["type"] == "integracao.falhou":
print("Falhou:", evento["data"]["nota_id"], evento["data"]["error"])
return "", 200
if __name__ == "__main__":
app.run(port=8080)<?php
// integracao.php: recebe "integracao.documentos" (DANFE gerado a partir do Bling ou do Tiny) e baixa os PDFs
function assinatura_valida(string $corpoCru, string $cabecalho, string $segredo, int $tolerancia = 300): bool {
$partes = [];
foreach (explode(',', $cabecalho) as $par) {
[$chave, $valor] = array_pad(explode('=', $par, 2), 2, '');
$partes[$chave] = $valor;
}
$t = (int) ($partes['t'] ?? 0);
if (!$t || empty($partes['v1']) || abs(time() - $t) > $tolerancia) return false;
return hash_equals(hash_hmac('sha256', $t . '.' . $corpoCru, $segredo), $partes['v1']);
}
$corpo = file_get_contents('php://input');
if (!assinatura_valida($corpo, $_SERVER['HTTP_X_CONVERTAJA_SIGNATURE'] ?? '', getenv('CONVERTAJA_WEBHOOK_SECRET'))) {
http_response_code(400);
exit;
}
$evento = json_decode($corpo, true);
if ($evento['type'] === 'integracao.documentos') {
foreach ($evento['data']['files'] as $f) { // links válidos por 7 dias
file_put_contents(basename($f['name']), file_get_contents($f['url']));
}
} elseif ($evento['type'] === 'integracao.falhou') {
error_log("DANFE da nota {$evento['data']['nota_id']} falhou: {$evento['data']['error']}");
}
http_response_code(200);
Passo 4: n8n, Zapier, Make e WooCommerce
As quatro usam a API com a sua chave. Enquanto os pacotes não estão nas lojas, peça o nó do n8n, o convite do Zapier, o app do Make ou o .zip do plugin pelo contato, ou faça o pedido direto pelo nó/módulo HTTP de cada ferramenta. Este é o pedido que todos fazem para gerar o DANFE a partir do link do XML:
# O mesmo pedido que o nó HTTP do n8n, o Webhooks by Zapier ou o módulo HTTP do Make fazem:
# XML da nota por URL (ex.: link do ERP ou do Google Drive) → DANFE 10×15, resposta na mesma chamada
curl -X POST "https://convertaja.com.br/v1/tools/xml-nfe-para-pdf?wait=true" \
-H "Authorization: Bearer $CONVERTAJA_KEY" \
-H "Content-Type: application/json" \
-d '{
"files": [{ "url": "https://seusite.com.br/notas/4521.xml" }],
"options": { "layout": "simplificado" }
}'// XML da nota por URL → DANFE 10×15 (o mesmo pedido de um fluxo no n8n, Zapier ou Make)
const res = await fetch('https://convertaja.com.br/v1/tools/xml-nfe-para-pdf?wait=true', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.CONVERTAJA_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
files: [{ url: 'https://seusite.com.br/notas/4521.xml' }],
options: { layout: 'simplificado' }, // ou "a4"
}),
});
const job = await res.json();
console.log(job.status, job.info, job.download_url);import os
import requests
# XML da nota por URL → DANFE 10×15 (o mesmo pedido de um fluxo no n8n, Zapier ou Make)
res = requests.post(
"https://convertaja.com.br/v1/tools/xml-nfe-para-pdf",
params={"wait": "true"},
headers={"Authorization": f"Bearer {os.environ['CONVERTAJA_KEY']}"},
json={
"files": [{"url": "https://seusite.com.br/notas/4521.xml"}],
"options": {"layout": "simplificado"}, # ou "a4"
},
timeout=90,
)
job = res.json()
print(job["status"], job.get("info"), job.get("download_url"))<?php
// XML da nota por URL → DANFE 10×15 (ex.: num plugin WooCommerce, ao concluir o pedido)
$ch = curl_init('https://convertaja.com.br/v1/tools/xml-nfe-para-pdf?wait=true');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 90,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CONVERTAJA_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'files' => [['url' => 'https://seusite.com.br/notas/4521.xml']],
'options' => ['layout' => 'simplificado'], // ou 'a4'
]),
]);
$job = json_decode(curl_exec($ch), true);
echo "{$job['status']} {$job['info']} {$job['download_url']}\n";
Dica No n8n, use o nó HTTP Request com autenticação Header Auth (Authorization: Bearer …); no Zapier, Webhooks by Zapier → Custom Request; no Make, HTTP → Make a request. Para não esperar a resposta, troque ?wait=true por webhook_url.
Limites e privacidade
- Bling e Tiny (beta): sem custo extra; até 30 notas por dia no plano grátis e 2.000 nos planos pagos. n8n, Zapier, Make e WooCommerce consomem créditos da API (1 crédito por XML no DANFE).
- Não guardamos o XML. Os PDFs ficam 7 dias no link; o histórico guarda só tipo do evento, número da nota e situação, por 30 dias.
- Se o ERP mandar um aviso num formato que não reconhecemos, o evento aparece como ignorado ou com erro em Eventos recentes, sem custo. Conte para a gente pelo contato.
Próximos passos
Todos os endpoints e opções: referência da API. Dúvidas? Fale com a gente e informe o X-Request-Id da chamada.