API do Pingu Link: Como Integrar o Encurtador ao Seu Site ou Bot
Uma chamada GET devolve o link curto em JSON. A chave exige nível 3. Parâmetros, formato da resposta, limite de chamadas e como tratar erro em produção.

Se você tem um bot, um site ou um sistema que precisa gerar links curtos automaticamente, a integração com o Pingu Link é uma única chamada HTTP. Sem SDK para instalar, sem autenticação em duas etapas, sem dependência para manter.
Antes de começar: a chave exige nível 3
A chave de API aparece sozinha na sua conta a partir do nível 3. Abaixo disso ela só é liberada por solicitação ao suporte.
Não é burocracia: a chave gera links na sua conta, e liberá-la para qualquer cadastro recém-criado seria um convite a abuso. Como se sobe de nível está em Sistema de Níveis do Pingu Link.
A chamada
Um GET com a sua chave e o endereço de destino:
GET https://pingulink.com/api?api=SUA_CHAVE&url=https://exemplo.com/pagina
A resposta vem em JSON:
{
"status": "success",
"message": "",
"shortenedUrl": "https://pingulink.com/a3f9"
}
E, em caso de erro, no mesmo formato:
{
"status": "error",
"message": "Invalid API token",
"shortenedUrl": ""
}
Repare que o erro também volta com HTTP 200. Quem trata só o código HTTP nunca vê a falha — o campo que decide é o status.
Os parâmetros
| Parâmetro | Obrigatório | O que faz |
|---|---|---|
api | sim | Sua chave |
url | sim | O endereço de destino |
alias | não | Escolhe o final do link em vez de sortear |
type | não | Quantidade de etapas, de 0 a 6 — sobrescreve a da chave |
format | não | json (padrão) ou text |
Com format=text a resposta é só o endereço, sem JSON — e, em caso de erro, vem vazia. É prático para colar direto numa mensagem, e perigoso se você não tratar o vazio.
A chave e as etapas
A chave é gerada no painel e carrega a própria configuração de etapas. Isso é mais útil do que parece à primeira vista: você não precisa passar esse parâmetro em cada chamada, e pode separar contextos sem tocar no código.
- Uma chave de 2 etapas para o bot que atende público novo.
- Uma chave de 4 etapas para o canal principal.
- Uma chave de 5 etapas para o conteúdo exclusivo.
Trocar a configuração vira uma mudança no painel, não um deploy. E quando você precisar de uma exceção pontual, o parâmetro type sobrescreve a chave só naquela chamada.
Segurança da chave
Trate a chave como senha, porque é uma: quem a tiver gera links na sua conta.
- Ela fica no servidor. Nunca em JavaScript que roda no navegador do visitante, nunca em aplicativo distribuído.
- Nunca em repositório. Use variável de ambiente. Chave commitada em repositório público é encontrada por robô em minutos.
- Revogue ao suspeitar. Gerar uma nova e trocar leva menos tempo que investigar.
Tratando a resposta
Sempre confira o campo status antes de usar o shortenedUrl. Integração que assume sucesso quebra silenciosamente no dia em que a chave for revogada ou o destino for recusado — e quebra em produção, não no teste.
const r = await fetch(url).then(r => r.json());
if (r.status === 'success') {
usar(r.shortenedUrl);
} else {
registrar(r.message);
usar(destinoOriginal); // entrega o link original
}
O padrão acima é o que eu recomendaria para qualquer integração: em caso de falha, entregue o link original. Você perde a receita daquela visita e não perde o usuário. O contrário — não entregar nada — perde os dois.
Boas práticas que evitam dor de cabeça
Guarde o resultado
Não gere o mesmo link várias vezes. Chamar a API a cada exibição desperdiça requisição e polui a sua lista com centenas de links idênticos, o que destrói as estatísticas.
Guarde o par destino → link curto no seu banco e reutilize.
Respeite um intervalo mínimo
Rajadas de centenas de chamadas por segundo são tratadas como abuso. Se você precisa gerar muitos links de uma vez, espace as chamadas.
Tenha um tempo limite
Se a API não responder em poucos segundos, siga com o link original em vez de travar o seu fluxo. Um bot que congela esperando resposta é pior que um bot que entrega link não monetizado.
const ctrl = new AbortController();
setTimeout(() => ctrl.abort(), 4000);
fetch(url, { signal: ctrl.signal })
Registre as falhas
Guarde o motivo de cada erro. Sem log, o dia em que a integração parar vira investigação às cegas — e normalmente é algo simples, como chave revogada ou destino bloqueado.
Onde isso costuma ser usado
- Bot de Telegram que entrega conteúdo. O caso mais comum: o bot gera o link na hora, a pessoa passa pelas etapas e recebe o que pediu.
- Site com área de downloads. Cada arquivo tem seu link gerado dinamicamente.
- Automação de publicação. O sistema publica em redes sociais já com o link monetizado.
- Encurtador interno. Sua ferramenta usa o Pingu Link por baixo, sem o usuário perceber.
Se o seu caso é o do Telegram, talvez você nem precise programar: existe um gerador de bots pronto que faz isso por configuração, incluindo convite temporário e remoção automática.
Exemplos em três linguagens
A integração é a mesma em qualquer lugar: um GET e a leitura de dois campos.
PHP
function encurtar(string $destino): string {
$url = 'https://pingulink.com/api?api=' . getenv('PGL_CHAVE')
. '&url=' . urlencode($destino);
$ctx = stream_context_create(['http' => ['timeout' => 4]]);
$bruto = @file_get_contents($url, false, $ctx);
$r = $bruto ? json_decode($bruto, true) : null;
// em caso de falha, o link original -- nunca nada
return (($r['status'] ?? '') === 'success') ? $r['shortenedUrl'] : $destino;
}
Python
import os, requests
def encurtar(destino):
try:
r = requests.get('https://pingulink.com/api', timeout=4, params={
'api': os.environ['PGL_CHAVE'],
'url': destino,
}).json()
return r['shortenedUrl'] if r.get('status') == 'success' else destino
except Exception:
return destino
Node
async function encurtar(destino) {
const u = new URL('https://pingulink.com/api');
u.searchParams.set('api', process.env.PGL_CHAVE);
u.searchParams.set('url', destino);
try {
const r = await fetch(u, { signal: AbortSignal.timeout(4000) })
.then(r => r.json());
return r.status === 'success' ? r.shortenedUrl : destino;
} catch {
return destino;
}
}
Repare no padrão comum aos três: toda falha devolve o destino original. É a decisão de projeto mais importante da integração — você perde a receita de uma visita e não perde o usuário.
Guardando o resultado
Chamar a API a cada exibição é o erro mais comum, e ele tem dois custos: desperdício de requisição e destruição das suas estatísticas, porque o mesmo destino vira centenas de links diferentes.
A correção é uma tabela de duas colunas:
CREATE TABLE links_curtos (
destino VARCHAR(500) NOT NULL,
curto VARCHAR(190) NOT NULL,
criado DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (destino(190))
);
Antes de chamar a API, consulte. Depois de receber, grave. Duas linhas de código que evitam milhares de chamadas por mês.
Ambiente de teste sem sujar a conta
Durante o desenvolvimento você vai gerar dezenas de links de mentira, e eles ficam para sempre na sua lista atrapalhando a leitura.
Duas soluções, ambas simples:
- Uma chave só para desenvolvimento. Você separa o que é teste do que é produção e pode revogá-la sem afetar nada.
- Um interruptor no código. Em ambiente local, a função devolve o destino original sem chamar a API.
if (process.env.NODE_ENV !== 'production') return destino;
A segunda é a que eu recomendaria: além de manter a conta limpa, ela deixa o desenvolvimento mais rápido, porque não há requisição de rede em cada teste.
Checklist antes de colocar em produção
- A chave está em variável de ambiente, não no código
- Existe tempo limite na requisição
- Falha devolve o destino original
- O resultado é guardado e reutilizado
- Erros são registrados com o motivo
- Ambiente local não chama a API
- A chave usada tem a quantidade de etapas correta para o contexto
- O código lê
statuseshortenedUrl, e não campos inventados
Oito itens. Os dois primeiros evitam incidente de segurança; os três seguintes evitam que a sua aplicação quebre por causa de um serviço externo; os três últimos evitam bagunça.
Testando antes de escrever código
Antes de integrar, confirme que a chave funciona. Uma linha no terminal:
curl -s "https://pingulink.com/api?api=SUA_CHAVE&url=https://exemplo.com"
Se voltar JSON com "status": "success", está tudo certo e o problema seguinte será só do seu código. Se voltar erro, você economizou uma tarde de depuração no lugar errado.
As mensagens de erro, e o que cada uma quer dizer
Todas voltam no campo message, sempre com HTTP 200:
| Mensagem | O que aconteceu |
|---|---|
Invalid API call | Faltou api ou url na chamada |
Invalid API token | Chave errada, desativada, ou conta do dono não está ativa |
Invalid URL | O destino não passou na validação |
Invalid alias | Alias fora do formato aceito ou reservado pelo sistema |
Alias already taken | Já existe, e não é seu com o mesmo destino |
Too many requests. Try again later. | Passou de 300 chamadas por minuto naquele IP |
Internal error | Falha do lado do servidor — vale repetir depois |
Os erros mais comuns na integração
| Sintoma | Causa provável |
|---|---|
Invalid API token sempre | Chave com espaço extra ao copiar, ou parâmetro escrito errado — é api, não outro nome |
| Funciona no terminal, falha no código | Falta codificar a URL de destino |
| Funciona local, falha em produção | Variável de ambiente não configurada no servidor |
Resposta vazia com format=text | Deu erro — o modo texto não devolve mensagem, só vazio |
| Links duplicados aos montes | Sem guardar o resultado; chamada a cada exibição |
O segundo é o que mais consome tempo. Um destino com ? ou & quebra a chamada se não for codificado — o parâmetro do destino é interpretado como parâmetro da própria API.
// errado
'...&url=' + destino
// certo
'...&url=' + encodeURIComponent(destino)
Limitando o estrago quando a API cai
Todo serviço externo fica fora do ar em algum momento. A pergunta não é se, é o que o seu sistema faz nesse minuto.
O padrão que resolve chama-se disjuntor: depois de algumas falhas seguidas, pare de tentar por um tempo e devolva o destino original direto.
let falhas = 0, pausaAte = 0;
async function encurtar(destino) {
if (Date.now() < pausaAte) return destino; // ainda em pausa
try {
const r = await chamarApi(destino);
falhas = 0;
return r.ok ? r.short : destino;
} catch {
if (++falhas >= 5) pausaAte = Date.now() + 60000;
return destino;
}
}
Sem isso, um serviço lento vira um problema seu: cada requisição do seu usuário fica esperando o tempo limite, a fila do seu servidor enche, e o que era indisponibilidade de terceiro vira indisponibilidade sua.
Com o disjuntor, a primeira falha custa quatro segundos e as seguintes custam zero. O usuário recebe o link original e não percebe nada.
Monitorando a integração
Duas métricas bastam, e as duas você já tem se estiver registrando os erros:
- Proporção de respostas com
status: "error". Se ela subir de repente, provavelmente a chave foi revogada ou você bateu no limite de chamadas. - Quantos links foram entregues sem encurtar. É receita que deixou de existir, e o número torna visível um problema que ninguém reclamaria.
O segundo é o mais útil dos dois. Uma integração quebrada não gera erro visível para o usuário — ele recebe o link e segue a vida. Sem essa métrica, dá para passar semanas sem perceber que a monetização parou.
Quando não usar a API
Vale dizer, porque programador tende a integrar por reflexo:
- Se você gera poucos links por mês. Criar à mão no painel é mais rápido que escrever e manter código.
- Se o seu caso é grupo de Telegram. O gerador de bots já resolve, com convite temporário e remoção automática — coisas que você levaria dias para implementar.
- Se os destinos são fixos. Um conjunto que não muda pode ser criado uma vez e reutilizado para sempre.
A API compensa quando o destino é dinâmico e o volume justifica o código. Fora disso, ela é trabalho a mais pelo mesmo resultado.
Perguntas frequentes
Existe limite de chamadas?
Sim: 300 chamadas por minuto por IP. Acima disso a resposta vira Too many requests. Try again later. por um período. Guarde o resultado e espace as chamadas.
Posso ter várias chaves?
Pode, e é recomendado — uma por projeto, cada uma com sua configuração de etapas.
A API aceita POST?
Não. É GET com os parâmetros na URL.
Posso escolher o final do link?
Pode, com o parâmetro alias. Se ele já estiver em uso por outra pessoa, a resposta é Alias already taken. Se já for seu e apontar para o mesmo destino, a API devolve o link existente em vez de dar erro — o que torna a chamada segura de repetir.
Como sei quanto cada chave rendeu?
As estatísticas do painel separam por link e por origem. Usar uma chave por projeto é o que torna essa leitura útil — veja como interpretar as estatísticas.
O link gerado por API é diferente?
Não. É o mesmo link, com as mesmas etapas e o mesmo pagamento de um criado à mão no painel.


