← blog

automatize seus links curtos com n8n (e com qualquer outra ferramenta)

toda ferramenta de automação sabe fazer uma requisição HTTP. é a única coisa que a API do arvore.link precisa que ela saiba.

o exemplo abaixo é no n8n, porque é o caso mais pedido e o que dá mais trabalho de acertar na primeira vez. no fim tem a versão curta para make, zapier e planilha — são as mesmas três decisões em qualquer lugar: a url, o cabeçalho, o corpo.

antes de tudo: o token

vá em painel → API e crie um token. ele começa com arv_ e aparece uma única vez — guardamos apenas um hash dele, então nem nós conseguimos mostrá-lo de novo. se perder, revogue e crie outro.

no plano gratuito são um token ativo e 100 requisições por hora. guarde esse número, ele volta a importar no fim.

o nó no n8n

adicione um nó HTTP Request e preencha quatro coisas:

methodPOST

urlhttps://api.arvore.link/links

authentication — escolha generic credential type, depois header auth, e crie uma credencial com:

name:  Authorization
value: Bearer arv_seu_token_aqui

o Bearer com espaço faz parte do valor. é o erro mais comum: sem ele a resposta é 401 com {"error":"UNAUTHORIZED"}, que parece token inválido e é só formato errado.

body — ligue send body, formato JSON, e mande:

{
  "url": "https://exemplo.com.br/promo",
  "tags": ["n8n"]
}

url é obrigatório. em vez do valor fixo, use uma expressão para pegar o link do nó anterior — {{ $json.url }}, ou o nome do campo que vier da sua planilha, do seu formulário, do seu RSS.

os nomes desses campos mudam de leve entre versões do n8n, mas as quatro decisões são sempre as mesmas: método, url, cabeçalho, corpo.

o que volta

{
  "id": "pf3lari6",
  "slug": "jhm0",
  "url": "https://exemplo.com.br/promo",
  "short_url": "https://arvr.ink/jhm0",
  "redirect_domain": "arvr.ink",
  "created_at": 1785359937465,
  "updated_at": 1785359937465,
  "deleted_at": null,
  "tags": ["n8n"]
}

o campo que você quer no próximo nó é short_url, como {{ $json.short_url }}. daí ele vai para onde precisa: uma coluna da planilha, um post agendado, uma mensagem no whatsapp, um campo do seu CRM.

slug é a parte curta sozinha, útil se você monta a url à mão em algum lugar.

as tags são o que salva isso depois

parece detalhe e não é. um fluxo que roda todo dia cria links todo dia, e em três meses você tem centenas sem saber qual veio de onde.

marque no próprio nó, com o valor fixo do fluxo (["n8n"], ["newsletter"], ["instagram-bot"]) ou com uma expressão que monte a tag a partir dos dados — ["campanha-{{ $json.campanha }}"].

tags aceitam minúsculas, números e hífen, no máximo 10 por link. no painel elas viram filtro: você clica na tag e vê só os links daquele fluxo, com os cliques de cada um.

testando a credencial sem criar lixo

antes de rodar o fluxo inteiro, teste o token com uma requisição que não cria nada:

method GET, url https://api.arvore.link/account, mesmo cabeçalho.

se voltar um json com user e workspace, a credencial está certa. se voltar 401, o problema é o cabeçalho — quase sempre o Bearer faltando.

erros, que é a parte que ninguém documenta

todo erro tem a mesma forma: error é sempre um código em texto.

{ "error": "UNAUTHORIZED" }

os que você vai encontrar num fluxo: UNAUTHORIZED (401, cabeçalho errado), LINK_ID_ALREADY_IN_USE (409, o slug que você pediu já existe), RATE_LIMITED (429, falou no limite) e VALIDATION_FAILED (400).

quando é validação, vem também um fields dizendo qual entrada está errada:

{
  "error": "VALIDATION_FAILED",
  "fields": { "url": ["Invalid URL"] }
}

isso importa para automação: você checa {{ $json.error }} — um texto, sempre — em vez de tentar adivinhar a estrutura. no n8n, ligue continue on fail se o fluxo não pode parar por causa de uma linha ruim, e use a saída de erro com um IF sobre {{ $json.error }} para separar "credencial errada" de "essa linha tem uma url inválida".

o limite de 100 por hora, e o que ele significa de verdade

100 requisições por hora por token é confortável para um fluxo que reage a eventos — um formulário respondido, um post publicado, um pedido novo.

não é suficiente para encher a planilha de uma vez. 500 linhas em um loop passam do limite na centésima e as outras 400 voltam 429 com um cabeçalho Retry-After dizendo quantos segundos faltam.

se for um backfill, coloque um nó Wait de 40 segundos dentro do loop e deixe rodando; ou faça em blocos de 100 por hora. é chato, e é honesto: o plano gratuito é para automatizar o dia a dia, não para migrar um acervo numa tarde.

as mesmas três coisas nas outras ferramentas

make — módulo HTTP → Make a request. method POST, url https://api.arvore.link/links, em headers adicione Authorization com Bearer arv_…, body type raw, content type JSON.

zapierWebhooks by Zapier → Custom Request. mesmo method e url, Headers com Authorization, Data com o json.

planilha do google — extensões → apps script:

function encurtar(url) {
  const r = UrlFetchApp.fetch("https://api.arvore.link/links", {
    method: "post",
    contentType: "application/json",
    headers: { Authorization: "Bearer arv_seu_token" },
    payload: JSON.stringify({ url: url, tags: ["planilha"] }),
    muteHttpExceptions: true,
  });
  return JSON.parse(r.getContentText()).short_url;
}

salve e use =encurtar(A2) numa célula. o muteHttpExceptions é para você ver a mensagem de erro em vez de um #ERROR! sem explicação.

terminal, para conferir qualquer coisa rapidamente:

curl -X POST https://api.arvore.link/links \
  -H "Authorization: Bearer arv_seu_token" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://exemplo.com.br/promo","tags":["teste"]}'

por que passar pelo encurtador em vez de usar o link direto

o fluxo funcionaria sem isso — você publicaria a url original e pronto. o que você ganha:

  • cada acesso é medido: país, dispositivo, navegador e de qual site a pessoa veio, em métricas;
  • o destino é editável depois: o link publicado continua valendo quando a página de destino mudar de endereço;
  • cabe em qualquer lugar: arvr.ink/jhm0 sobra num sms, num cartão, numa bio.

comece

crie sua conta, pegue um token em painel → API e veja a documentação completa — todos os endpoints, com o objeto que cada um devolve.