Introdução
O Link Builder nasceu como uma necessidade interna da Ad Rock Digital Mkt: automatizar a geração de links rastreáveis (UTM) e QR Codes para campanhas digitais.
Com o tempo, o projeto evoluiu de um simples script Python para uma API robusta, integrada a um Custom GPT, e hoje serve como base para futuras automações com o OpenAI Assistants API.

Tela do CustomGPT com a pergunta inicial onde o usuário inseri os valores para gerar o link.
O Desafio Inicial
Na rotina da Ad Rock, o time de mídia precisava criar rapidamente links parametrizados para campanhas no Google Ads, Meta Ads e newsletters, garantindo rastreabilidade via GA4.
O problema?
Processos manuais, suscetíveis a erros.
Falta de padronização de nomenclaturas.
Necessidade de gerar QR Codes individualmente para cada link.
A solução ideal deveria:
Gerar links UTM automaticamente.
Produzir QR Codes prontos para uso.
Registrar logs de cada criação.
Ser acessível via API para integração com ferramentas de IA e automação.
A Construção da API com Flask
O backend foi construído em Flask, pela leveza e flexibilidade.
A estrutura base ficou assim:
link_builder/
├── main.py
├── database.py
├── static/
├── templates/
├── openapi.yaml
├── .well-known/
├── requirements.txt
└── README.md
link_builder/
├── main.py
├── database.py
├── static/
├── templates/
├── openapi.yaml
├── .well-known/
├── requirements.txt
└── README.md
link_builder/
├── main.py
├── database.py
├── static/
├── templates/
├── openapi.yaml
├── .well-known/
├── requirements.txt
└── README.md

Tela do backend do Flask para teste de inserção dos links.

Tela do backend do Flask confirmando links inseridos.
O arquivo main.py é o coração da aplicação.
Ele:
Recebe JSON com parâmetros UTM.
Constrói a URL rastreável.
Gera QR Code em base64.
Retorna tudo via JSON.
Exemplo de payload:
{
"url": "https://adrock.com.br/parcerias",
"utm_source": "newsletter",
"utm_medium": "email",
"utm_campaign": "parcerias-2025"
}{
"url": "https://adrock.com.br/parcerias",
"utm_source": "newsletter",
"utm_medium": "email",
"utm_campaign": "parcerias-2025"
}{
"url": "https://adrock.com.br/parcerias",
"utm_source": "newsletter",
"utm_medium": "email",
"utm_campaign": "parcerias-2025"
}E o retorno:
{
"utm_url": "https://adrock.com.br/parcerias?utm_source=newsletter&utm_medium=email&utm_campaign=parcerias-2025",
"short_url": "https://tinyurl.com/xyz",
"qrcode": "data:image/png;base64,iVBORw0K..."
}{
"utm_url": "https://adrock.com.br/parcerias?utm_source=newsletter&utm_medium=email&utm_campaign=parcerias-2025",
"short_url": "https://tinyurl.com/xyz",
"qrcode": "data:image/png;base64,iVBORw0K..."
}{
"utm_url": "https://adrock.com.br/parcerias?utm_source=newsletter&utm_medium=email&utm_campaign=parcerias-2025",
"short_url": "https://tinyurl.com/xyz",
"qrcode": "data:image/png;base64,iVBORw0K..."
}Persistência e Logs
Foi implementado um SQLite local (link_history.db) que registra:
Data de criação.
URL base.
Parâmetros UTM.
QR Code gerado.
Isso garante histórico completo e fácil exportação para CSV.
Infraestrutura e Deploy
A aplicação roda na DigitalOcean, com:
Ubuntu 22.04 LTS
Python 3.10
Nginx como proxy reverso
Certbot (Let’s Encrypt) para SSL
Systemd service garantindo execução automática
Trecho do linkbuilder.service:
[Unit]
Description=Link Builder Flask App
After=network.target
[Service]
User=root
WorkingDirectory=/home/adrock/bots/link_builder
ExecStart=/usr/bin/python3 /home/adrock/bots/link_builder/main.py
Restart=always
[Install]
WantedBy=multi-user.target
[Unit]
Description=Link Builder Flask App
After=network.target
[Service]
User=root
WorkingDirectory=/home/adrock/bots/link_builder
ExecStart=/usr/bin/python3 /home/adrock/bots/link_builder/main.py
Restart=always
[Install]
WantedBy=multi-user.target
[Unit]
Description=Link Builder Flask App
After=network.target
[Service]
User=root
WorkingDirectory=/home/adrock/bots/link_builder
ExecStart=/usr/bin/python3 /home/adrock/bots/link_builder/main.py
Restart=always
[Install]
WantedBy=multi-user.target
E o bloco principal do Nginx:
server {
listen 443 ssl;
server_name linkbuilder.mobiledelivery.com.br;
ssl_certificate /etc/letsencrypt/live/linkbuilder.mobiledelivery.com.br/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/linkbuilder.mobiledelivery.com.br/privkey.pem;
root /home/adrock/bots/link_builder;
location /openapi.yaml {
alias /home/adrock/bots/link_builder/openapi.yaml;
add_header Access-Control-Allow-Origin "*";
add_header Content-Type "application/yaml";
}
location /.well-known/ai-plugin.json {
alias /home/adrock/bots/link_builder/.well-known/ai-plugin.json;
add_header Access-Control-Allow-Origin "*";
add_header Content-Type "application/json";
}
location / {
proxy_pass http:
proxy_set_header Host $host;
}
}server {
listen 443 ssl;
server_name linkbuilder.mobiledelivery.com.br;
ssl_certificate /etc/letsencrypt/live/linkbuilder.mobiledelivery.com.br/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/linkbuilder.mobiledelivery.com.br/privkey.pem;
root /home/adrock/bots/link_builder;
location /openapi.yaml {
alias /home/adrock/bots/link_builder/openapi.yaml;
add_header Access-Control-Allow-Origin "*";
add_header Content-Type "application/yaml";
}
location /.well-known/ai-plugin.json {
alias /home/adrock/bots/link_builder/.well-known/ai-plugin.json;
add_header Access-Control-Allow-Origin "*";
add_header Content-Type "application/json";
}
location / {
proxy_pass http:
proxy_set_header Host $host;
}
}server {
listen 443 ssl;
server_name linkbuilder.mobiledelivery.com.br;
ssl_certificate /etc/letsencrypt/live/linkbuilder.mobiledelivery.com.br/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/linkbuilder.mobiledelivery.com.br/privkey.pem;
root /home/adrock/bots/link_builder;
location /openapi.yaml {
alias /home/adrock/bots/link_builder/openapi.yaml;
add_header Access-Control-Allow-Origin "*";
add_header Content-Type "application/yaml";
}
location /.well-known/ai-plugin.json {
alias /home/adrock/bots/link_builder/.well-known/ai-plugin.json;
add_header Access-Control-Allow-Origin "*";
add_header Content-Type "application/json";
}
location / {
proxy_pass http:
proxy_set_header Host $host;
}
}Integração com Custom GPT (OpenAI Plugin Manifest)
Para uso via ChatGPT, o projeto recebeu um plugin manifest (ai-plugin.json) hospedado em .well-known/, permitindo integração direta com GPT Actions.

Tela do CustomGPT inserindo instruções do Bot.
Exemplo do manifesto:
{
"schema_version": "v1",
"name_for_human": "Ad Rock Link Builder",
"name_for_model": "link_builder_agent",
"description_for_human": "Gera links com parâmetros UTM e QR Codes automaticamente.",
"auth": {"type": "none"},
"api": {
"type": "openapi",
"url": "https://linkbuilder.mobiledelivery.com.br/openapi.yaml"
},
"logo_url": "https://linkbuilder.mobiledelivery.com.br/static/images/logo-sem-fundo.png",
"contact_email": "rafael@adrock.com.br",
"legal_info_url": "https://adrock.com.br"
}{
"schema_version": "v1",
"name_for_human": "Ad Rock Link Builder",
"name_for_model": "link_builder_agent",
"description_for_human": "Gera links com parâmetros UTM e QR Codes automaticamente.",
"auth": {"type": "none"},
"api": {
"type": "openapi",
"url": "https://linkbuilder.mobiledelivery.com.br/openapi.yaml"
},
"logo_url": "https://linkbuilder.mobiledelivery.com.br/static/images/logo-sem-fundo.png",
"contact_email": "rafael@adrock.com.br",
"legal_info_url": "https://adrock.com.br"
}{
"schema_version": "v1",
"name_for_human": "Ad Rock Link Builder",
"name_for_model": "link_builder_agent",
"description_for_human": "Gera links com parâmetros UTM e QR Codes automaticamente.",
"auth": {"type": "none"},
"api": {
"type": "openapi",
"url": "https://linkbuilder.mobiledelivery.com.br/openapi.yaml"
},
"logo_url": "https://linkbuilder.mobiledelivery.com.br/static/images/logo-sem-fundo.png",
"contact_email": "rafael@adrock.com.br",
"legal_info_url": "https://adrock.com.br"
}Essa integração permitiu criar o Custom GPT “Ad Rock – Link Builder 1.0”, que conversa diretamente com a API Flask e gera QR Codes sem sair do ChatGPT.

Tela do CustomGPT inserindo o schema da API no endpoint.
Desafios Técnicos
1. Permissões e Deploy
Um dos maiores entraves foi a correção de permissões entre root, staff e www-data, que impediam leitura de arquivos pelo Nginx.
Solução: normalização com chmod e chown específicos.
2. Configuração de Proxy e SSL
Erros de roteamento (404/403) ocorreram até definir corretamente os blocos de localização (location /openapi.yaml e .well-known/ai-plugin.json).
3. Geração do QR Code em base64
Inicialmente, o retorno era apenas um blob ilegível.
A solução foi renderizar a imagem inline no próprio JSON, permitindo visualização imediata no ChatGPT e no navegador.

Tela do resultado gerado com o link parametrizado e o QRCode para download.
O Futuro: Evolução para o Assistant
O próximo passo do projeto é integrá-lo com o OpenAI Assistants API, permitindo:
Receber comandos em linguagem natural como:
“Crie um link para a campanha de Natal com Google Ads e QR Code para Instagram.”
Chamar o endpoint /create-utm automaticamente.
Retornar link e QR Code formatados na resposta.
Essa abordagem transformará o Link Builder em um middleware inteligente entre o usuário e a API — eliminando a necessidade de prompts estruturados e tornando o processo 100% natural.

Tela do Assistant sendo preparado para o Middleware.
Conclusão
O Link Builder é um exemplo prático de como unir engenharia backend, automação com IA e infraestrutura profissional para resolver um problema real de marketing digital.
Ele representa o DNA da Ad Rock:
estratégia, tecnologia e automação, conectadas para gerar resultados mensuráveis.
👉 Está no ar em: https://github.com/adrockmkt/link_builder