Referência de API
Integre GPUs de topo de linha à sua aplicação. Simples, rápido e confiável.
URL base
Todos os endpoints ficam sob a URL base abaixo e respondem em JSON:
https://gpubrasil.com.br
Autenticação
Autentique com uma API key no header Authorization. A key não expira e pode ser revogada a qualquer momento no painel. Trate-a como uma senha — quem tiver a key pode criar e apagar instâncias na sua conta.
Authorization: Bearer gpub_live_suachaveaqui
Alternativamente, você pode enviar a key no header x-api-key.
Gere sua API key no painel
Por segurança, as API keys são geradas e gerenciadas dentro da sua conta — na seção API Keys do painel. A chave em claro é exibida uma única vez, no ambiente autenticado.
Abrir painel → API KeysEndpoints
Fluxo completo
O ciclo de vida de uma instância é: escolher a GPU → criar → consultar status/conexão → (opcional) parar/iniciar → deletar. Nos exemplos abaixo, defina sua chave em uma variável de ambiente:
export GPUB_API_KEY="gpub_live_suachaveaqui"
1. Listar GPUs e preços
Retorna o catálogo com preço por hora (em R$) e o gpu_key que você usa para criar a instância. Não exige autenticação.
curl -s "https://gpubrasil.com.br/api/gpus"
Resposta (resumo):
{
"gpus": [
{ "model": "NVIDIA H100 PCIe 80GB", "gpu_key": "premium_H100-80G-PCIe",
"pricePerHourBrl": 19.88, "provider": "premium" },
{ "model": "RTX 4090", "gpu_key": "economic_RTX_4090",
"pricePerHourBrl": 3.34, "provider": "economic" }
]
}
Dica: use /api/gpus/available para ver também a quantidade disponível em tempo real.
Só as GPUs compatíveis com um template
Os templates de 1 clique não rodam em qualquer máquina: cada um exige um mínimo de memória de vídeo, e alguns só funcionam em instância de máquina virtual Dedicada. Passe ?template=<id> em /api/gpus e o catálogo volta já filtrado, pelas mesmas regras que o deploy aplica.
curl -s "https://gpubrasil.com.br/api/gpus?template=llama-factory"
Resposta (resumo):
{
"template": { "id": "llama-factory", "name": "LLaMA-Factory",
"minVramGb": 16, "diskGb": 80, "requiresVm": false },
"gpus": [
{ "model": "RTX 4090", "gpu_key": "economic_RTX_4090", "gpuRamGb": 24,
"pricePerHourBrl": 3.34, "templateMinGpuCount": 1 }
]
}
Os ids de template vêm de GET /api/templates. templateMinGpuCount é o mínimo de GPUs a pedir no deploy (campo gpuCount) para o template caber na máquina — 1 na maioria, mais de 1 nos modelos grandes, que somam a memória das placas. Id desconhecido devolve 400 com TEMPLATE_NOT_FOUND.
Filtrar o catálogo
O catálogo tem centenas de entradas. Em vez de baixar tudo e escolher no seu código, peça já filtrado:
# 4090 abaixo de R$ 4/h nas Américas, mais barata primeiro curl -s "https://gpubrasil.com.br/api/gpus?model=4090&max_price_brl=4®ion=NA&sort=price&limit=5" # qualquer placa com 80 GB de memória de vídeo ou mais, tier Dedicada curl -s "https://gpubrasil.com.br/api/gpus?min_vram_gb=80&tier=dedicada&sort=price"
| Parâmetro | O que faz |
|---|---|
tier | dedicada, economica, spot (aceita lista separada por vírgula). |
model / q | Pedaço do nome do modelo (4090, h100). |
max_price_brl / min_price_brl | Teto e piso de preço por hora, em reais. |
min_vram_gb | Memória de vídeo mínima por placa. |
region | Macro-região: NA (América do Norte), EU, AP (Ásia-Pacífico) ou GL (qualquer região). |
gpu_count | Quantas placas você quer. Esconde os modelos que só saem em bloco maior que isso — evita descobrir a restrição só na hora do deploy. |
available | true deixa só o que tem unidade livre agora. |
supports_templates / video_encoder | Só máquinas que rodam template de 1 clique / que têm codificador de vídeo (streaming e vídeo). |
sort / order / limit | Ordena por price, vram ou model; order=desc inverte; limit corta a lista. |
Com filtro, a resposta ganha count (o que sobrou) e total (o tamanho do catálogo). Sem filtro, o formato é o de sempre. Preço e disponibilidade mudam ao longo do dia: consulte perto da hora de criar a máquina, não uma vez por semana.
2. Criar instância
Use o gpuModel = gpu_key obtido no passo 1. O deploy roda em segundo plano; a resposta volta na hora com um instanceId e status creating.
curl -X POST "https://gpubrasil.com.br/api/instances/deploy" \
-H "Authorization: Bearer $GPUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "minha-vm",
"gpuModel": "premium_H100-80G-PCIe",
"vcpuCount": 8,
"ramGb": 64,
"storageGb": 100
}'
Resposta:
{
"success": true,
"instance": { "instanceId": "abc123", "name": "minha-vm", "status": "creating" },
"chargedAmount": 19.88,
"currency": "R$",
"message": "Instância sendo criada..."
}
| Campo | Padrão | O que é |
|---|---|---|
gpuModel (obrigatório) | — | O gpu_key que veio do catálogo. |
name | gerado | O nome pelo qual você vai operar a máquina depois. Até 64 caracteres. Veja Gerenciar pelo nome. |
gpuCount | 1 | Quantas placas. Alguns modelos só saem em bloco — o catálogo diz o mínimo em minGpuCount. |
vcpuCount · ramGb · storageGb | 4 · 16 · 100 | Mínimos aceitos: 2 vCPU, 8 GB de RAM, 40 GB de disco. |
sshKey ou sshKeyName | — | A chave pública inteira, ou o nome de uma já cadastrada no painel. É o seu acesso à máquina. |
templateId | — | Template de 1 clique. Use /api/gpus?template=<id> para ver onde ele roda. |
diskId | — | Disco Persistente a anexar. Aceita o id ou name:<nome do disco>. |
metadata | — | Suas etiquetas (objeto JSON simples): id do job, lote, ambiente. Viram filtro na listagem. |
requireUniqueName | false | true recusa a criação (409 NAME_IN_USE, sem cobrar) se já existir máquina ativa com aquele nome. |
A resposta devolve instanceId na hora — guarde-o, ou use o name que você escolheu. O valor em chargedAmount é a primeira hora, pré-paga: a cobrança seguinte só acontece se a máquina passar dessa hora. Se o provisionamento falhar, esse valor volta para o seu saldo automaticamente.
3. Status e dados de conexão SSH
Consulte pelo instanceId — ou pelo nome que você deu, com name:<nome>. Quando o status virar running, o objeto connection traz IP, porta e o comando SSH pronto (já com o usuário de login correto daquela máquina).
curl -s "https://gpubrasil.com.br/api/instances/abc123" \
-H "Authorization: Bearer $GPUB_API_KEY"
Resposta:
{
"id": "abc123",
"name": "minha-vm",
"status": "running",
"gpu_model": "premium_H100-80G-PCIe",
"connection": {
"ip": "203.0.113.42",
"port": 22,
"user": "ubuntu",
"sshCommand": "ssh -i ~/.ssh/your_key -p 22 ubuntu@203.0.113.42"
},
"resources": { "vcpuCount": 8, "ramGb": 64, "storageGb": 100 },
"pricing": { "hourlyRateBrl": 19.88 }
}
4. Listar e filtrar suas instâncias
A listagem aceita filtros. Se você opera dezenas de máquinas ao mesmo tempo, peça só o que interessa em vez de baixar tudo e procurar no seu código.
# tudo
curl -s "https://gpubrasil.com.br/api/instances" -H "Authorization: Bearer $GPUB_API_KEY"
# só o que está rodando, do lote da noite, 10 por página, mais novas primeiro
curl -s "https://gpubrasil.com.br/api/instances?status=running&metadata.lote=noite&limit=10" \
-H "Authorization: Bearer $GPUB_API_KEY"
Resposta:
{
"data": [
{
"instance_id": "abc123",
"name": "treino-noturno",
"status": "running",
"tier": "economica",
"gpu_model": "RTX_4090@NA",
"gpu_model_label": "RTX 4090 · América do Norte",
"gpu_count": 1,
"ip_address": "203.0.113.42",
"ssh_port": 22,
"ssh_user": "root",
"ssh_key_name": "deploy-ci",
"supports_pause": false,
"disk_persists_on_stop": false,
"price_per_hour_brl": 3.34,
"daily_stopped_brl": 3.94,
"metadata": { "job": "7f21", "lote": "noite" },
"template_id": null, "template_port": null, "template_url": null,
"error_message": null, "deleting": false,
"created_at": "2026-09-18 22:14:02"
}
],
"count": 1,
"total": 1,
"limit": 10,
"offset": 0
}
Filtros aceitos
| Parâmetro | Exemplo | O que faz |
|---|---|---|
name | ?name=treino-noturno | Nome exato (maiúsculas não importam). |
q / name_contains | ?q=treino | Pedaço do nome. Ótimo para prefixos de esteira (?q=job-2026-09). |
status | ?status=running,stopped | Um ou vários status, separados por vírgula. |
tier | ?tier=dedicada,spot | dedicada, economica, spot ou cpu. |
gpu | ?gpu=4090 | Pedaço do modelo da GPU. |
template | ?template=llama-factory | Só as máquinas criadas com aquele template de 1 clique. |
has_ip | ?has_ip=true | Só as que já têm endereço para conectar. |
metadata.<chave> | ?metadata.job=7f21 | Filtra pelas etiquetas que você mesmo gravou. |
created_after / created_before | ?created_after=2026-09-01 | Janela de criação (data ISO, em UTC). |
sort / order | ?sort=name&order=asc | Ordena por created_at (padrão), name, price ou status. |
limit / offset | ?limit=20&offset=40 | Paginação. limit vai até 500; sem ele, vem tudo. |
Filtros combinam entre si. count é o que veio nesta página e total é quanto o filtro encontrou no total — é a diferença entre os dois que diz se falta paginar. O campo localInstances continua na resposta com o mesmo conteúdo de data, por compatibilidade com integrações antigas; em código novo use data.
Campos que valem atenção
| Campo | Por que existe |
|---|---|
ssh_user | O usuário de login daquela máquina, reportado no provisionamento. Não deduza do tipo da máquina: máquinas do mesmo tier podem ter logins diferentes. |
ssh_key_name | Qual das suas chaves cadastradas foi instalada — é a privada correspondente que vai no -i do ssh. |
supports_pause | Se false, esta máquina não hiberna: /stop devolve 409. Para encerrar, use DELETE. |
disk_persists_on_stop | Se false, hibernar descarta o disco e a máquina volta zerada. Confira antes de parar. |
template_url | Endereço real da interface do template, com a porta que de fato responde (em máquina de contêiner ela é sorteada e não é a do catálogo). null enquanto não houver endereço de verdade. |
deleting / status: "deleting" | Cancelamento já aceito, aguardando o provisionador liberar a destruição. A cobrança por hora já parou — não repita o DELETE. |
error_message | Motivo da falha em linguagem de gente, quando status é error. |
5. Gerenciar pelo nome, sem listar tudo
Toda rota que aceita :instanceId aceita também name:<nome>. Você batiza a máquina na criação e passa a operá-la por esse nome — sem guardar o id que geramos e sem baixar a lista inteira para procurar a cada comando.
# cria com um nome seu
curl -X POST "https://gpubrasil.com.br/api/instances/deploy" \
-H "Authorization: Bearer $GPUB_API_KEY" -H "Content-Type: application/json" \
-d '{ "name": "treino-noturno", "gpuModel": "economic_RTX_4090", "requireUniqueName": true }'
# e daí em diante opera pelo nome, em qualquer rota
H="Authorization: Bearer $GPUB_API_KEY"
curl -s "https://gpubrasil.com.br/api/instances/name:treino-noturno" -H "$H"
curl -s -X POST "https://gpubrasil.com.br/api/instances/name:treino-noturno/stop" -H "$H"
curl -s -X DELETE "https://gpubrasil.com.br/api/instances/name:treino-noturno" -H "$H"
Regras que valem a pena conhecer antes de automatizar:
| Regra | Por quê |
|---|---|
O id sempre ganha do nome. Sem o prefixo name:, primeiro procuramos um id; só se não existir é que tratamos o texto como nome. | Integração que já usa id não muda de comportamento, nem que alguém batize uma máquina com o id de outra. |
| O nome endereça só máquinas ativas. | Nome se repete ao longo do tempo (uma esteira recria worker todo dia). Casar com uma máquina já destruída mandaria comandos para o vazio. |
Maiúsculas não importam: name:Treino-01 e name:treino-01 resolvem igual. | Quem digita o nome não deveria ter que lembrar a capitalização. |
Dois nomes iguais ativos = 409 AMBIGUOUS_NAME, com a lista dos candidatos. Nunca escolhemos por você. | "Apaga a treino-01" acertando a máquina errada é dano que não volta atrás. |
HTTP 409 — duas máquinas ativas com o mesmo nome
{
"code": "AMBIGUOUS_NAME",
"error": "Existem 2 instâncias ativas com o nome \"treino-noturno\". Use o id da instância (veja \"matches\") ou renomeie uma delas.",
"matches": [
{ "id": "abc123", "name": "treino-noturno", "status": "running", "gpu_model_label": "RTX 4090", "created_at": "2026-09-18 22:14:02" },
{ "id": "def456", "name": "treino-noturno", "status": "creating", "gpu_model_label": "RTX 4090", "created_at": "2026-09-19 03:40:11" }
]
}
Para garantir que o nome continue sendo um endereço único, mande "requireUniqueName": true no deploy: se já existir máquina ativa com aquele nome, a criação é recusada com 409 NAME_IN_USE — sem cobrar nada — e a resposta diz qual máquina já ocupa o nome. Sem esse campo, o comportamento antigo continua valendo (nomes repetidos são aceitos).
6. Renomear e etiquetar
PATCH /api/instances/:ref corrige o nome e grava etiquetas suas (metadata) na máquina — id do job, lote, ambiente, o que a sua esteira precisar reencontrar depois.
curl -X PATCH "https://gpubrasil.com.br/api/instances/name:treino-noturno" \
-H "Authorization: Bearer $GPUB_API_KEY" -H "Content-Type: application/json" \
-d '{ "name": "treino-noturno-v2", "metadata": { "job": "7f21", "lote": "noite", "tentativa": 2 } }'
Resposta:
{ "success": true, "instance": { "id": "abc123", "name": "treino-noturno-v2",
"metadata": { "job": "7f21", "lote": "noite", "tentativa": 2 }, "status": "running", ... } }
| Campo | Regras |
|---|---|
name | Até 64 caracteres: letras, números, espaço, ponto, @, hífen e sublinhado. Não pode começar com name: nem creating- (são prefixos de endereçamento). Nome já usado por outra máquina ativa sua devolve 409 NAME_IN_USE. |
metadata | Objeto JSON simples: até 20 chaves, valores de texto, número ou booleano (sem objetos aninhados), 2 KB no total. Mandar null apaga as etiquetas. |
Renomear só é permitido depois que a máquina existe de verdade (status running/stopped). Durante a criação, a resposta é 409 RENAME_TOO_EARLY: enquanto o provisionamento está em curso, o nome ainda é a chave que usamos internamente para reconciliar a máquina — trocá-lo ali abriria uma janela para a máquina ficar fora do nosso controle de cobrança. Espere o running, que leva de segundos a poucos minutos.
As etiquetas voltam prontas (como objeto, não como texto) em GET /api/instances e viram filtro: ?metadata.lote=noite.
7. Quanto esta máquina já custou
GET /api/instances/:ref/usage devolve a conta fechada daquela instância — incluindo a primeira hora pré-paga, que não aparece em nenhum contador de uso por hora.
curl -s "https://gpubrasil.com.br/api/instances/name:treino-noturno/usage" \
-H "Authorization: Bearer $GPUB_API_KEY"
Resposta:
{
"id": "abc123",
"name": "treino-noturno",
"status": "running",
"currency": "BRL",
"hourly_rate_brl": 3.34,
"daily_stopped_brl": 3.94,
"total_charged_brl": 13.36,
"breakdown": { "hourly_usage_brl": 10.02, "reservations_net_brl": 3.34 },
"created_at": "2026-09-18 22:14:02",
"last_charged_at": "2026-09-19 01:14:02",
"age_hours": 4.12
}
| Campo | O que é |
|---|---|
total_charged_brl | Tudo que já saiu do seu saldo por esta máquina, com estornos já descontados. É este o número para relatório de custo. |
breakdown.hourly_usage_brl | As horas inteiras já fechadas e cobradas. |
breakdown.reservations_net_brl | A hora pré-paga na criação (e a de cada religada), menos estornos. |
daily_stopped_brl | Quanto custa um dia com a máquina hibernada. Não é 1× o preço/hora: a GPU é liberada, mas o disco continua reservado. É o número que decide entre hibernar e destruir. |
last_charged_at | Última hora fechada. A próxima cobrança acontece uma hora depois desta marca. |
8. Parar e iniciar (opcional)
Parar interrompe a cobrança por hora, mas não zera o custo: enquanto parada, a instância passa a ser cobrada em uma diária equivalente a 1 hora de uso. Atenção: nem toda máquina preserva o disco ao parar — em parte das máquinas do tipo Dedicada o disco é descartado e a instância volta zerada no start, perdendo tudo que foi instalado nela. Confira o campo disk_persists_on_stop em GET /api/instances antes de parar. Para encerrar a cobrança por completo, use DELETE.
Nem toda máquina hiberna: onde a placa é devolvida ao parar, não haveria como garantir a mesma máquina de volta. O campo supports_pause diz quais aceitam — nas outras, /stop devolve 409 em vez de destruir a máquina sem você pedir.
curl -X POST "https://gpubrasil.com.br/api/instances/name:minha-vm/stop" \ -H "Authorization: Bearer $GPUB_API_KEY" curl -X POST "https://gpubrasil.com.br/api/instances/name:minha-vm/start" \ -H "Authorization: Bearer $GPUB_API_KEY"
9. Deletar instância
Destrói a instância no provedor e encerra a cobrança. É o endpoint que você perguntou — ele existe e é definitivo.
curl -X DELETE "https://gpubrasil.com.br/api/instances/name:minha-vm" \
-H "Authorization: Bearer $GPUB_API_KEY"
Resposta:
{ "success": true, "message": "Instância removida" }
Se a máquina ainda estiver sendo criada, a destruição pode ser recusada (HTTP 409) — tente de novo em alguns minutos. Quando a resposta vier como 202 (ou a instância aparecer com status: "deleting"), o pedido já foi aceito e a cobrança por hora já parou: não repita o DELETE, a destruição termina sozinha.
Outros recursos da conta
Tudo abaixo usa a mesma API key e o mesmo saldo em reais. E, como nas instâncias, disco e chave SSH também podem ser endereçados pelo nome que você deu.
Máquinas de CPU (sem GPU)
Para pré-processamento, fila, scraping e serviços que não precisam de placa de vídeo. São máquinas dedicadas de verdade, com opção em São Paulo.
# catálogo (público)
curl -s "https://gpubrasil.com.br/api/cpus"
# criar
curl -X POST "https://gpubrasil.com.br/api/cpus/deploy" \
-H "Authorization: Bearer $GPUB_API_KEY" -H "Content-Type: application/json" \
-d '{ "name": "fila-etl", "cpu_key": "cpu_c3-small-x86@SAO2", "sshKeyName": "deploy-ci",
"metadata": { "lote": "etl" }, "requireUniqueName": true }'
Depois de criada, a máquina de CPU aparece e é operada pelas mesmas rotas de instância (listar, status, renomear, deletar), com tier: "cpu". O provisionamento é de máquina física e leva alguns minutos — mais que uma GPU. Chave SSH é obrigatória (é o único acesso).
Disco Persistente
Armazenamento que sobrevive à destruição da máquina. Você anexa um disco na criação e o conteúdo de /workspace/disco é sincronizado; na próxima máquina, anexe o mesmo disco e os dados voltam.
# criar um disco de 100 GB
curl -X POST "https://gpubrasil.com.br/api/disks" \
-H "Authorization: Bearer $GPUB_API_KEY" -H "Content-Type: application/json" \
-d '{ "name": "dados-treino", "sizeGb": 100 }'
# listar / achar pelo nome
curl -s "https://gpubrasil.com.br/api/disks?name=dados-treino" -H "Authorization: Bearer $GPUB_API_KEY"
# anexar na criação da máquina — pelo NOME do disco
curl -X POST "https://gpubrasil.com.br/api/instances/deploy" \
-H "Authorization: Bearer $GPUB_API_KEY" -H "Content-Type: application/json" \
-d '{ "name": "treino-01", "gpuModel": "economic_RTX_4090", "diskId": "name:dados-treino" }'
# renomear / apagar (apagar destrói os dados)
curl -X PATCH "https://gpubrasil.com.br/api/disks/name:dados-treino" -H "Authorization: Bearer $GPUB_API_KEY" \
-H "Content-Type: application/json" -d '{ "name": "dados-treino-2026" }'
curl -X DELETE "https://gpubrasil.com.br/api/disks/name:dados-treino-2026" -H "Authorization: Bearer $GPUB_API_KEY"
O disco é cobrado pelo tamanho contratado (não pelo usado) enquanto existir, mesmo sem máquina anexada. Dois discos com o mesmo nome fazem qualquer comando por nome devolver 409 AMBIGUOUS_NAME em vez de escolher um — apagar o disco errado é perda de dados que não volta.
Chaves SSH
Cadastre a chave uma vez e depois só cite o nome dela no deploy, com sshKeyName — sem carregar o material da chave dentro da sua esteira.
curl -X POST "https://gpubrasil.com.br/api/ssh-keys" \
-H "Authorization: Bearer $GPUB_API_KEY" -H "Content-Type: application/json" \
-d '{ "name": "deploy-ci", "publicKey": "ssh-ed25519 AAAAC3Nza... ci@empresa" }'
curl -s "https://gpubrasil.com.br/api/ssh-keys" -H "Authorization: Bearer $GPUB_API_KEY"
# apagar pelo nome
curl -X DELETE "https://gpubrasil.com.br/api/ssh-keys/name:deploy-ci" -H "Authorization: Bearer $GPUB_API_KEY"
No deploy, mande sshKey (a chave pública inteira) ou sshKeyName (o nome de uma já cadastrada). Nome que não existe devolve 400 SSH_KEY_NOT_FOUND e não cria máquina nenhuma — máquina paga e inacessível é o pior desfecho possível. O campo ssh_key_name da instância diz qual chave acabou instalada.
Saldo e extrato
curl -s "https://gpubrasil.com.br/api/user/balance" -H "Authorization: Bearer $GPUB_API_KEY"
{ "balance_brl": 482.15, "user": { "id": 42, "name": "...", "email": "..." } }
# extrato, com recorte
curl -s "https://gpubrasil.com.br/api/transactions?type=reservation,usage&limit=100" \
-H "Authorization: Bearer $GPUB_API_KEY"
curl -s "https://gpubrasil.com.br/api/transactions?q=treino-noturno" -H "Authorization: Bearer $GPUB_API_KEY"
| Parâmetro | O que faz |
|---|---|
type | deposit, reservation, usage, refund — aceita lista separada por vírgula. |
q | Busca no texto do lançamento (é nele que o nome da máquina aparece). |
created_after / created_before | Janela de datas, para fechar o mês. |
limit / offset | Paginação (padrão 50, máximo 500). |
Convenção do extrato: cobrança é valor negativo e crédito é positivo. As datas vêm em UTC. A resposta é um array puro.
Receitas prontas
Subir, esperar ficar pronta e conectar
O deploy responde na hora com status: "creating"; a máquina fica utilizável alguns instantes depois. Consulte pelo nome até o status virar running com IP:
NOME="treino-$(date +%s)"
curl -sX POST "https://gpubrasil.com.br/api/instances/deploy" \
-H "Authorization: Bearer $GPUB_API_KEY" -H "Content-Type: application/json" \
-d "{\"name\":\"$NOME\",\"gpuModel\":\"economic_RTX_4090\",\"sshKeyName\":\"deploy-ci\",\"requireUniqueName\":true}"
# espera até 15 min, perguntando a cada 10 s
for i in $(seq 1 90); do
J=$(curl -s "https://gpubrasil.com.br/api/instances/name:$NOME" -H "Authorization: Bearer $GPUB_API_KEY")
S=$(echo "$J" | python3 -c "import json,sys; print(json.load(sys.stdin)['status'])")
[ "$S" = "running" ] && echo "$J" | python3 -c "import json,sys; print(json.load(sys.stdin)['connection']['sshCommand'])" && break
[ "$S" = "error" ] && echo "$J" | python3 -c "import json,sys; print('falhou:', json.load(sys.stdin)['error_message'])" && break
sleep 10
done
Intervalo de 5 a 10 segundos entre consultas é suficiente e educado. O campo connection.sshCommand já vem montado com o usuário certo daquela máquina; troque só o caminho da sua chave privada no -i.
Derrubar um lote inteiro pelo prefixo do nome
Use o filtro por pedaço do nome (ou por etiqueta) e destrua cada uma pelo id — que a própria listagem já devolveu.
# tudo que começa com "job-2026-09-19"
curl -s "https://gpubrasil.com.br/api/instances?q=job-2026-09-19&status=running" \
-H "Authorization: Bearer $GPUB_API_KEY" \
| python3 -c "import json,sys; [print(i['instance_id']) for i in json.load(sys.stdin)['data']]" \
| while read ID; do
curl -sX DELETE "https://gpubrasil.com.br/api/instances/$ID" -H "Authorization: Bearer $GPUB_API_KEY"
done
O mesmo vale por etiqueta: ?metadata.lote=noite. Prefira apagar pelo id devolvido na listagem quando for lote: é imune a nome repetido.
Quanto gastei hoje, por máquina
for NOME in $(curl -s "https://gpubrasil.com.br/api/instances?status=running" \
-H "Authorization: Bearer $GPUB_API_KEY" \
| python3 -c "import json,sys; [print(i['name']) for i in json.load(sys.stdin)['data']]"); do
curl -s "https://gpubrasil.com.br/api/instances/name:$NOME/usage" -H "Authorization: Bearer $GPUB_API_KEY" \
| python3 -c "import json,sys; d=json.load(sys.stdin); print(f\"{d['name']}: R\$ {d['total_charged_brl']:.2f} ({d['age_hours']:.1f}h)\")"
done
Vocabulário de status
| status | O que significa | Está cobrando? |
|---|---|---|
creating | Provisionamento em curso. Ainda sem IP. | Sim — a primeira hora é pré-paga na criação. |
running | No ar e utilizável. connection traz IP, porta e usuário. | Sim, por hora. |
stopped | Hibernada (só onde supports_pause é true). | Sim, uma diária de armazenamento — veja daily_stopped_brl. |
deleting | Cancelamento aceito, aguardando a destruição terminar. | Não. Não repita o DELETE. |
error | Falhou. O motivo está em error_message. | Não — o que foi reservado é estornado automaticamente. |
stopped_no_balance | Desligada por saldo insuficiente. | Como parada. Recarregue e use /start. |
Limites de uso
| Limite | Valor | Quando você encosta nele |
|---|---|---|
| Criação de máquinas | 40 por 10 minutos, por conta | 429, com Retry-After em segundos. É proteção contra laço em retry, não teto comercial: precisa de mais, é só pedir. |
| Consultas de leitura | sem limite fixo | Pedimos bom senso: intervalo de 5 a 10 s ao aguardar uma máquina subir, e filtro em vez de listar tudo em laço. |
| Chaves SSH cadastradas | 10 por conta | 400 ao cadastrar a 11ª. |
| Tamanho do disco | 10 GB a 10 TB | 400 fora da faixa. |
Inferência por token (compatível com OpenAI)
Nem todo projeto precisa de uma GPU inteira ligada. Você também pode chamar modelos de pesos abertos pagando por token consumido, usando a mesma API key gpub_live_ e o mesmo saldo em reais que paga as GPUs. Não existe assinatura, não existe mensalidade e não existe mínimo de compra de tokens: a cobrança é proporcional aos tokens de entrada e de saída de cada chamada, e o valor debitado volta na própria resposta.
A API é compatível com a da OpenAI. Qualquer SDK, framework ou ferramenta que já converse com ela funciona aqui trocando apenas a URL base e a chave:
https://gpubrasil.com.br/v1
Não usamos seus prompts nem suas respostas para treinar modelos. Se o seu caso exige controle total sobre os pesos, os logs e o ciclo de vida do que trafega, rode o modelo em uma GPU dedicada só sua, sem API de terceiro no caminho.
1. Listar modelos e preços
Devolve os modelos disponíveis, o tamanho da janela de contexto e o preço por milhão de tokens, em reais. Cada modelo tem um id, que é o que vai no campo model, um name comercial para exibição e uma prateleira.
São três prateleiras: fronteira (modelos de marca — Claude, GPT e Gemini), confidenciais (rodam dentro de um enclave lacrado por hardware) e essenciais (pesos abertos, melhor preço por token). Todos respondem pelo mesmo formato da OpenAI, inclusive os que na origem exigiriam outro formato de requisição.
curl -s "https://gpubrasil.com.br/v1/models" \
-H "Authorization: Bearer $GPUB_API_KEY"
Resposta (resumo):
{
"object": "list",
"data": [
{ "id": "gpub-fast", "object": "model", "owned_by": "gpubrasil",
"name": "DeepSeek V4 Flash", "prateleira": "essenciais", "context_length": 1000000,
"pricing": { "currency": "BRL", "inputPerMillion": 0.59, "cachedInputPerMillion": 0.118, "outputPerMillion": 1.29 } },
{ "id": "claude-sonnet-5", "object": "model", "owned_by": "gpubrasil",
"name": "Claude Sonnet 5", "prateleira": "fronteira", "context_length": 1000000,
"pricing": { "currency": "BRL", "inputPerMillion": 20.40, "cachedInputPerMillion": 2.04, "outputPerMillion": 102.00 } },
{ "id": "gpub-selado-nemotron", "object": "model", "owned_by": "gpubrasil",
"name": "Nemotron 3 Nano", "prateleira": "confidenciais", "context_length": 128000,
"pricing": { "currency": "BRL", "inputPerMillion": 0.15, "cachedInputPerMillion": 0.015, "outputPerMillion": 0.60 } }
]
}
O exemplo acima está resumido a três linhas, uma de cada prateleira; a chamada devolve o catálogo inteiro. A lista completa, sempre atual, está em Modelos de IA. Precisa da tabela sem autenticar (para uma página de preços, por exemplo)? Use GET /api/inference/models, que é público.
2. Chat completion
Formato idêntico ao da OpenAI. A única diferença é o campo extra usage.cost_brl: o custo em reais daquela chamada, já calculado pelo servidor e já debitado do seu saldo, para você não precisar refazer a conta no cliente.
curl -X POST "https://gpubrasil.com.br/v1/chat/completions" \
-H "Authorization: Bearer $GPUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpub-plus",
"messages": [
{ "role": "system", "content": "Você responde em português do Brasil." },
{ "role": "user", "content": "Explique o que é uma GPU em duas frases." }
],
"max_tokens": 300
}'
Resposta:
{
"id": "chatcmpl-8f2c1b",
"object": "chat.completion",
"created": 1754870400,
"model": "gpub-plus",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Uma GPU é um processador..." },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 500,
"completion_tokens": 300,
"total_tokens": 800,
"cost_brl": 0.0085,
"balance_brl_after": 92.15
}
}
O campo model da resposta devolve o que você pediu (aqui, gpub-plus), não o identificador técnico — se você chamar por apelido, é o apelido que volta. cost_brl (custo da chamada) e balance_brl_after (saldo depois dela) são acréscimos nossos dentro do objeto usage; o cabeçalho X-Request-Id identifica a requisição no nosso lado, guarde-o se precisar abrir um chamado. SDKs oficiais ignoram campos que não conhecem, então esses extras não quebram nenhuma integração existente. Para continuação de texto puro (sem papéis de conversa), o endpoint é POST /v1/completions, com prompt no lugar de messages.
Imagem e áudio na entrada. Use o bloco image_url padrão da OpenAI dentro de content — funciona em todos os modelos que aceitam imagem, em qualquer prateleira, sem mudar nada no seu código. Para áudio, o bloco é input_audio. Se o modelo escolhido não aceitar o que você mandou, a resposta é 400 com o motivo; nunca aceitamos a chamada ignorando a parte que o modelo não entende. Em alguns modelos a imagem precisa ir embutida (data:<mime>;base64,…) em vez de URL, e o erro diz quando é o caso.
curl -X POST "https://gpubrasil.com.br/v1/chat/completions" \
-H "Authorization: Bearer $GPUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-5",
"max_tokens": 300,
"messages": [{
"role": "user",
"content": [
{ "type": "text", "text": "O que há de errado neste diagrama?" },
{ "type": "image_url", "image_url": { "url": "data:image/png;base64,iVBORw0KG..." } }
]
}]
}'
3. Streaming
Mande "stream": true para receber a resposta em pedaços, no padrão server-sent events. Para receber também o consumo e o custo, peça stream_options: {"include_usage": true}: o usage chega em um frame próprio, logo antes do [DONE].
curl -N -X POST "https://gpubrasil.com.br/v1/chat/completions" \
-H "Authorization: Bearer $GPUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpub-fast",
"messages": [{ "role": "user", "content": "Conte até três." }],
"stream": true,
"stream_options": { "include_usage": true }
}'
Resposta (text/event-stream):
data: {"id":"chatcmpl-3a91","object":"chat.completion.chunk","model":"gpub-fast","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-3a91","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"Um"},"finish_reason":null}]}
data: {"id":"chatcmpl-3a91","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":", dois"},"finish_reason":null}]}
data: {"id":"chatcmpl-3a91","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":", três."},"finish_reason":null}]}
data: {"id":"chatcmpl-3a91","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"id":"chatcmpl-3a91","object":"chat.completion.chunk","choices":[],"usage":{"prompt_tokens":14,"completion_tokens":9,"total_tokens":23,"cost_brl":0.0000155,"balance_brl_after":92.15}}
data: [DONE]
Sem stream_options, o frame de usage não é enviado e você fica sem o cost_brl daquela chamada. O consumo continua registrado no servidor e aparece em /api/inference/usage. Encerre a leitura ao ver data: [DONE], que não é JSON.
4. SDK oficial da OpenAI
Não é preciso trocar de biblioteca. Aponte o SDK oficial para a nossa URL base e use a sua API key; o resto do código continua igual.
Python (pip install openai)
from openai import OpenAI
client = OpenAI(
base_url="https://gpubrasil.com.br/v1",
api_key="gpub_live_suachaveaqui",
)
r = client.chat.completions.create(
model="gpub-mini",
messages=[{"role": "user", "content": "Olá!"}],
)
print(r.choices[0].message.content)
# cost_brl é um campo extra nosso; no SDK Python ele chega em model_extra
print(r.usage.model_extra["cost_brl"])
Node.js (npm i openai)
import OpenAI from 'openai';
const client = new OpenAI({
baseURL: 'https://gpubrasil.com.br/v1',
apiKey: process.env.GPUB_API_KEY,
});
const r = await client.chat.completions.create({
model: 'gpub-mini',
messages: [{ role: 'user', content: 'Olá!' }],
});
console.log(r.choices[0].message.content);
console.log(r.usage.cost_brl); // custo em reais desta chamada
Vale o mesmo para ferramentas que aceitam um endpoint compatível com a OpenAI: preencha a URL base com https://gpubrasil.com.br/v1 e a chave com a sua gpub_live_.
5. Geração de imagem
Modelos que geram imagem têm superfície própria: POST /v1/images/generations, no mesmo formato da OpenAI, com a mesma chave e o mesmo saldo. Eles não atendem em /v1/chat/completions — pedir um ali devolve 400 apontando para cá, e vice-versa. O campo endpoint de cada modelo em GET /v1/models diz qual é a superfície dele.
curl -X POST "https://gpubrasil.com.br/v1/images/generations" \
-H "Authorization: Bearer $GPUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpub-imagem",
"prompt": "uma praça arborizada ao amanhecer, estilo aquarela",
"size": "1024x1024"
}'
Resposta:
{
"created": 1789807470,
"data": [ { "b64_json": "/9j/4AAQSkZJRgABAQ..." } ]
}
A imagem volta em b64_json (base64), pronta para gravar em arquivo. n precisa ser 1: estes modelos geram uma imagem por chamada, e pedir mais devolve 400 antes de reservar qualquer valor do seu saldo. size aceita uma lista fechada de tamanhos — mandar um fora dela devolve 400 com a lista inteira no erro. Alguns modelos não aceitam size; nesses, omita o campo.
Cobrança. Depende do modelo, e o preço de cada um está em GET /v1/models: uns cobram por imagem (campo perImage, em reais) e outros cobram por token de imagem (campo imageOutputPerMillion). A contagem sai sempre do que foi entregue, nunca do que foi pedido — resposta sem imagem não gera cobrança.
Limites, contexto e saldo
Janela de contexto. Entrada e saída somadas precisam caber no context_length do modelo escolhido, que hoje vai de 128.000 a 1.000.000 de tokens conforme o modelo. Passar disso devolve 400, sem cobrança. O valor de cada modelo está em GET /v1/models — consulte de lá em vez de fixar no código, porque modelo novo entra e janela muda.
Tamanho da resposta. max_tokens limita quantos tokens o modelo pode gerar. Sem ele, o modelo decide onde parar dentro da janela, e como a saída custa mais que a entrada em todos os modelos, vale definir um teto em produção.
Saldo. Antes de encaminhar a chamada, o servidor estima o custo. Se o seu saldo não cobrir essa estimativa, a requisição é recusada com 402 e nada é gasto. Recarregue por Pix no painel e tente de novo. A inferência pela API é liberada depois do primeiro depósito confirmado: antes disso a chamada volta com 403 e code: "deposit_required" — para experimentar sem depositar, use o playground do painel. Um excesso de chamadas em pouco tempo devolve 429; uma indisponibilidade momentânea devolve 503.
HTTP 402
{
"error": {
"message": "Saldo insuficiente para cobrir o custo estimado desta chamada.",
"type": "insufficient_quota",
"param": null,
"code": "insufficient_balance"
}
}
Os erros seguem o envelope da OpenAI (error.message, error.type, error.param, error.code), então bibliotecas existentes já sabem lê-los. Repare que type e code não são iguais: saldo curto vem como type: "insufficient_quota" e code: "insufficient_balance". Trate a decisão pelo status HTTP. Para acompanhar gasto e volume, use GET /api/inference/usage?days=30, que devolve o consumo por dia e por modelo.
Códigos de Resposta
200 · OK
Requisição bem-sucedida
201 · Criado
Instância/recurso criado
400 · Erro
Parâmetros inválidos ou saldo insuficiente
401 · Não autorizado
API key ausente, inválida ou revogada
403 · Proibido
Ação não permitida para esta credencial
402 · Saldo insuficiente
O saldo não cobre o custo estimado da chamada
429 · Limite de requisições
Muitas requisições em pouco tempo
404 · Não encontrado
Instância/recurso inexistente
409 · Conflito
Instância ainda sendo criada — tente depois
500 · Erro interno
Erro no servidor
Campo code nos erros
Além do status HTTP, os erros das rotas de instância trazem um code estável — trate por ele, não pelo texto da mensagem (que muda de idioma e de redação).
| code | HTTP | O que fazer |
|---|---|---|
INSTANCE_NOT_FOUND | 404 | O id/nome não existe entre as suas máquinas ativas. Nome só endereça máquina viva. |
AMBIGUOUS_NAME | 409 | Duas ou mais máquinas ativas com o mesmo nome. Use um dos ids que vêm em matches, ou renomeie. |
NAME_IN_USE | 409 | O nome já é de outra máquina ativa sua. Nada foi criado nem cobrado. |
RENAME_TOO_EARLY | 409 | Espere a máquina sair de creating para renomear. |
INVALID_NAME · INVALID_METADATA | 400 | Nome ou etiquetas fora das regras. Nada foi criado nem cobrado. |
SSH_KEY_NOT_FOUND | 400 | sshKeyName não bate com nenhuma chave sua. Veja GET /api/ssh-keys. |
DELETE_PENDING | 409 | A máquina já está sendo destruída; parar/iniciar não se aplica. |
PRICE_CHANGED | 409 | O preço mudou entre a consulta e o deploy. Releia o catálogo e tente de novo — nunca cobramos acima do que você viu. |
TEMPLATE_NOT_FOUND · TEMPLATE_REQUIRES_GPU | 400 | Template inexistente ou incompatível com a máquina escolhida. Use /api/gpus?template=<id> para listar só o que roda. |
INSUFFICIENT_BALANCE | 402 | Saldo não cobre a primeira hora. A resposta diz quanto falta. |
DISK_NOT_FOUND · DISK_UNSUPPORTED_MACHINE | 404 / 400 | Disco inexistente, ou tipo de máquina que ainda não aceita Disco Persistente. |
Regra geral: toda recusa acontece antes de qualquer cobrança. Se a resposta foi 4xx, nenhum valor saiu do seu saldo. E se uma máquina falha depois de criada, a reserva é estornada automaticamente — você não precisa pedir.