API Pro: saldo, limites e personagens treinados

Duas rotas de leitura, sempre permitidas independentemente das permissões da chave, mais o registo de atividade guardado na app.

Saldo e limites

GET /credits

json
{ "balance": 1830, "licenseId": "lic_...", "key": "k_1a2b3c4d",
  "limits": { "concurrent": 2, "perMinute": 60, "perDay": 0 }, "running": 1,
  "buy_url": "https://tendre.ai/credits?license=lic_..." }
CampoSignificado
balanceCréditos restantes. null quando o saldo é desconhecido (ambiente de teste).
licenseIdA licença à qual esta chave pertence.
keyO identificador público da chave, seguro para registar em logs. Nunca o segredo.
limits.concurrentRenders a correr ao mesmo tempo, 2 por defeito.
limits.perMinuteSubmissões por minuto, 60 por defeito.
limits.perDayLimite diário de créditos que definiste para a chave. 0 significa sem limite.
runningRenders desta chave ainda à espera de serem recolhidos.
buy_urlA página de compra de créditos da tua licença, por cartão ou cripto.

Esta é a chamada mais barata da API e a ideal para verificar se uma chave funciona.

Comprar créditos com o teu cartão guardado

POST /credits/purchase

json
{ "pack": "m" }

pack é um id de pack (s, m, l, xl, xxl ou xxxl), ou "c25000" para uma quantidade livre acima do maior pack. O pagamento é feito com o cartão guardado no carregamento automático da tua página de conta, apenas se aí autorizaste o teu agente a comprar, dentro do limite mensal que fixaste (carregamentos automáticos incluídos). Um e-mail confirma cada compra. Uma compra de cada vez.

A resposta é 200 { credits, eur, balance }. Cada recusa inclui buy_url, o link de compra normal, para usar em alternativa: 402 confirmation_required (o teu banco pede a tua confirmação) ou payment_declined; 409 agent_not_allowed, no_saved_card, monthly_cap_reached, topup_in_progress ou purchase_in_progress; 400 unknown_pack. Com 503 payment_unavailable não sabemos se o débito foi feito: não tentes de novo de imediato, um débito feito é creditado.

Personagens treinados

Estes são os personagens treinados como LoRA, para imagens e vídeos normais. Os personagens do Multi-Ref Vídeo, sete vistas feitas a partir de uma foto, são outra coisa: consulta Characters.

GET /loras

json
{ "image": [ { "name": "megan_krea2", "trigger": "megan", "base": "krea2", "size": 0 } ],
  "video": [ { "name": "megan_ltx", "trigger": "megan", "size": 0 } ] }

Passa name como lora, retirado da lista image para imagens e da lista video para vídeos, e coloca o seu trigger no prompt, caso contrário o personagem não aparecerá. Um personagem que não pertence à conta responde com 403 unknown_lora.

Carrega o teu próprio LoRA

POST /loras/upload

Um ficheiro .safetensors que já tens, treinado noutro lugar ou alojado no teu próprio servidor, é adicionado ao espaço da conta e fica disponível através de lora, exatamente como um personagem treinado na app. Há duas formas de o fazer: de uma vez até 90 MB, ou em partes acima disso. Um LoRA pesa normalmente entre 200 e 500 MB, por isso a segunda opção é o caso habitual. O limite máximo é 800 MB em ambos os casos.

De uma vez: corpo bruto (application/octet-stream, Content-Length obrigatório), parâmetros no URL.

Acima de 100 MB o pedido nunca chega à API. A infraestrutura à frente rejeita-o, por isso o que se recebe é um simples 413 sem corpo JSON: um cliente que tente analisar todos os erros como JSON vai falhar em vez de reportar o problema. Esse tamanho deve ser enviado em partes.

ParâmetroFunção
nameNome do ficheiro, .safetensors, letras, dígitos, . _ -, no máximo 80 caracteres. Um nome já existente é substituído.
kindimage (valor por defeito) ou video. Requer a permissão images ou videos respetivamente.
triggerA palavra de ativação a colocar no prompt, no máximo 60 caracteres.
bash
curl -s -X POST "$B/loras/upload?name=my_character.safetensors&kind=image&trigger=ohwx"   -H "Authorization: Bearer $KEY" -H "Content-Type: application/octet-stream"   --data-binary @my_character.safetensors

A resposta é { "ok": true, "name": "my_character.safetensors", "kind": "image", "size": 314572800, "trigger": "ohwx", "architecture": "krea2", "storage": { ... } }.

A compatibilidade é verificada no momento do carregamento. As imagens são geradas pelo Krea 2, que tem uma arquitetura própria: só um LoRA Krea 2 é aplicado, quer tenha sido treinado no tendre.AI ou para Krea 2 noutro lugar. Nota que um LoRA FLUX.1 é recusado, o que nem toda a gente adivinhou à primeira. Os vídeos são gerados pelo LTX 2.5, por isso um LoRA LTX 2.5 ou 2.3.

A API lê o cabeçalho do ficheiro antes de guardar qualquer coisa. Um LoRA reconhecido como SDXL, SD 1.5, SD3, FLUX.1, Wan ou HunyuanVideo é recusado com 415 incompatible_lora, que indica a architecture encontrada, e um ficheiro que não seja safetensors recebe 415 invalid_safetensors. Nada é guardado e nenhuma quota é consumida em nenhum dos casos.

Há uma situação que ainda passa: uma arquitetura que o cabeçalho não identifica é aceite, com architecture: "inconnue", e só é avaliada no momento da geração. Esse é o único erro que te custa um render para descobrires.

Envia um LoRA grande em partes

Três chamadas, mais uma para desistir.

1. Abre a sessão. POST /loras/upload/start com { "name", "kind", "size", "trigger" }, onde size é o ficheiro completo em bytes. Verifica o nome, o tamanho e a quota, e responde:

json
{ "uploadId": "...", "part_size": 20971520, "max_part_size": 104857600, "parts_expected": 15 }

2. Envia cada parte. POST /loras/upload/part?uploadId=...&part=N, corpo bruto, partes numeradas a partir de 1, part_size bytes cada uma exceto a última, nunca mais de max_part_size. Cada resposta inclui um etag, e precisas de todos eles para o passo seguinte, por isso guarda-os à medida que avança.

A parte 1 é especial: contém o cabeçalho do ficheiro, por isso é aí que a arquitetura é avaliada. Um LoRA incompatível é detetado nesse ponto com 415 e a sessão é cancelada. Ficas a saber ao fim de 20 MB em vez de 400.

3. Fecha a sessão. POST /loras/upload/finish com { "uploadId", "parts": [ { "part": 1, "etag": "..." }, ... ] }. Monta o ficheiro e regista-o, respondendo exatamente como o carregamento de uma só vez.

Para desistir, POST /loras/upload/abort com { "uploadId" }. Uma sessão deixada sem finish é eliminada ao fim de seis horas. Nada aparece em GET /loras e nada conta para a quota até que finish seja concluído com sucesso, por isso um carregamento interrompido não te custa armazenamento.

python
import os, requests
B, H = "https://api.tendre.ai/pro/v1", {"Authorization": "Bearer " + KEY}
path = name = "my_character.safetensors"
s = requests.post(f"{B}/loras/upload/start", headers=H,
                  json={"name": name, "kind": "image", "size": os.path.getsize(path), "trigger": "ohwx"}).json()
parts = []
with open(path, "rb") as f:
    n = 1
    while chunk := f.read(s["part_size"]):
        r = requests.post(f"{B}/loras/upload/part",
                          headers={**H, "Content-Type": "application/octet-stream"},
                          params={"uploadId": s["uploadId"], "part": n}, data=chunk)
        r.raise_for_status()
        parts.append({"part": n, "etag": r.json()["etag"]})
        n += 1
done = requests.post(f"{B}/loras/upload/finish", headers=H,
                     json={"uploadId": s["uploadId"], "parts": parts}).json()
print(done["name"], done["architecture"], done["storage"])

Um script PowerShell já pronto é incluído com a app, em scripts/api-pro-lora.ps1.

Elimina um LoRA

DELETE /loras/{name}?kind=image|video remove o ficheiro e liberta a quota. Responde com { "ok": true, "name": ..., "storage": { ... } }, ou 404 unknown_lora quando o nome não existe na conta.

Quota de armazenamento

Cada licença tem no máximo 20 ficheiros e 10 GB, imagens e vídeos juntos, e os personagens treinados na app contam para esse total. GET /loras reporta o estado em storage:

json
{ "count": 3, "max_count": 20, "bytes": 943718400, "max_bytes": 10737418240 }

Quando qualquer um dos limites é atingido, um carregamento responde com 413 lora_quota indicando o que resta. Elimina um ficheiro para libertar espaço.

Treinar um personagem ainda não está exposto pela API. Acontece na app e o resultado aparece nesta lista.

Atividade

A app mantém o registo de cada render feito pelas tuas chaves (data, chave, tipo, custo, estado) e o consumo por chave, em Configurações > API > Atividade.

É também aí que revogás uma chave que tenha sido comprometida, sem afetar as outras.

Windows · Mac · Cloud ou local

Gera em privado. Esta noite.

Descarrega a tendre.AI gratuitamente e gera sem limites, de forma privada, na tua própria GPU.

OS Windows 10/11GPU NVIDIA 8GB+VRAM 12GB recomendadoDisco 20GB

Mac: Apple silicon (M1 ou posterior), macOS 13 ou posterior. Os Macs Intel não são suportados.

A geração local de imagens no Mac precisa de um M4 com 24 GB de memória, ou um M2 ou M3 Pro, Max ou Ultra com 24 GB. Abaixo disso, tudo corre online com créditos. Por agora, a retoque e o vídeo correm online no Mac.

Tudo sobre o tendre.AI para Mac

Sem GPU NVIDIA? Começa 100% na cloud: 5 imagens grátis e 1 vídeo grátis todos os dias. Uma placa NVIDIA (8GB+) desbloqueia a geração local ilimitada.