Pular para o artigo

API do Solta

Tudo o que a interface faz, ela faz por aqui. Não existe outro caminho, e é também por isso que um agente conectado à sua conta não alcança nada que você não alcançaria.

Autenticação

Uma chave criada em Configurações → Chaves e conexões → Chaves de API, enviada como bearer token. Ela aparece uma vez só e é guardada como hash, então um vazamento do nosso banco de dados não vira uma lista de chaves que funcionam.

curl https://solta.now/v1/me \
  -H "Authorization: Bearer solta_…"

Os conectores usam OAuth: veja Conectar o Claude ou o ChatGPT. Os dois levam à mesma conta, com a mesma autoridade.

Publicar um arquivo

curl -X POST https://solta.now/v1/sites \
  -H "Authorization: Bearer solta_…" \
  -H "Content-Type: application/json" \
  -d '{"source": "export default () => <h1>hi</h1>",
       "filename": "App.tsx",
       "title": "Hello",
       "channel": "api"}'

Devolve o slug, o número da versão e o link. Envie um cabeçalho Idempotency-Key e repetir a mesma requisição não publica duas vezes.

Uma pessoa no Free tem 3 sites no ar ao mesmo tempo, somando a própria biblioteca e os espaços de trabalho Free de que é dona, e no Plus 15 sites nas bibliotecas Plus. Pro e Team não têm limite. No limite, um site novo (um arquivo, uma pasta ou um remix) recebe um 402 com o código site_limit: nada é publicado, e a resposta lista os sites no ar, cada um com a sua library, quantos precisam sair (toUnpublish), e a libraryUrl e a upgradeUrl. Em vez disso, adicione uma versão a um dos sites, o que mantém o link dele, ou abra espaço antes: POST /v1/sites/{id}/offline tira um site do ar sem perder nada, e POST /v1/sites/{id}/online o coloca de volta, o que é recusado do mesmo jeito no limite. Uma versão nova de um site nunca é recusada por isso.

Publicar uma pasta

Um endpoint separado, porque o corpo é um arquivo, não JSON. Envie o arquivo compactado como archive, ou uma url de onde devemos lê-lo.

curl -X POST https://solta.now/v1/sites/archive \
  -H "Authorization: Bearer solta_…" \
  -F "archive=@dist.zip" \
  -F "title=My site"

Os arquivos que um site não usa ficam de fora, e o resto é publicado: tudo o que pode guardar segredos (.env e todo .env.*, .npmrc, chaves privadas, credentials.json), arquivos e pastas ocultos como .git, e tipos que não servimos, como código de servidor. A resposta lista esses arquivos em skipped, cada um com o seu path e um reason que é secret, hidden ou unsupported, e diz o mesmo em warnings, para uma pessoa ler. Uma pasta com o código-fonte de um app, e não com o build dele, recebe um 422 com o código needs_build.

Uma versão nova é um rascunho. O link continua mostrando o que mostrava até você publicá-la, e isso leva duas chamadas de propósito, para nada ir ao ar por acidente.

POST /v1/sites/{id}/versions            → { number: 2, state: "draft" }
POST /v1/sites/{id}/versions/2/publish  → { number: 2, state: "live" }

Ou uma chamada só: "publish": true na primeira coloca a versão no ar na hora, a menos que o site precise de aprovação. Nesse caso, a resposta traz awaitsApproval: true e a versão espera como rascunho.

De vez em quando, as nossas verificações pedem que uma pessoa olhe uma página antes de ela ir ao ar, normalmente em até um dia. A resposta traz então held: { url }: o link do site avisa que a página está sendo verificada até ela ser liberada, e url é uma página que diz em que pé está a verificação, onde quem publicou sem conta pode deixar um e-mail para ser avisado. Publicar de novo não muda nada.

Uma pasta muda pelos arquivos. POST /v1/sites/{id}/versions/files recebe multipart form data: files para adicionar (um .zip entre eles é aberto, e um arquivo com um nome que já existe substitui o anterior), um remove para cada caminho a tirar, e replace=true quando o envio é o site inteiro. Com publish=true, a versão vai ao ar na mesma chamada, a menos que o site precise de aprovação. Nesse caso, a resposta traz awaitsApproval: true e a versão espera como rascunho. Entre vários arquivos, ou num .zip, o que uma pasta deixa de fora também fica de fora aqui, listado em skipped. Já um arquivo enviado sozinho que não publicaríamos é recusado.

O resto

GET /v1/library
Os seus sites.
GET /v1/sites/{slug}
Um site, a versão no ar e o histórico.
PATCH /v1/sites/{id}/visibility
Quem pode abrir o site.
PATCH /v1/sites/{id}
O título, ou o endereço, com { "slug": "…" }. O endereço antigo continua levando as pessoas adiante. Um endereço curto, de 4 caracteres ou menos, ou um endereço de uma palavra só, uma palavra comum sozinha, exige Pro ou Team: no Free, é um 402 com code: "needs_pro_short_address", e passando dos endereços curtos ou de uma palavra que o plano permite, short_address_limit. Um endereço com o nome de uma empresa ou de um banco é um 422 com slug_brand, em qualquer plano.
GET, POST /v1/sites/{id}/addresses
Os endereços do site, e mais um, com { "slug": "…" }, que leva os visitantes ao principal (Pro e Team). POST …/addresses/{slug}/main torna um deles o endereço principal, e DELETE …/addresses/{slug} o transforma num endereço antigo. Recusado com needs_pro_extra_address, extra_address_limit, needs_pro_short_address, short_address_limit, slug_brand ou slug_taken.
GET /v1/sites/{id}/compare?from=1&to=2
O que mudou entre duas versões.
DELETE /v1/sites/{id}
O site sai do ar na hora. O endereço fica reservado por pelo menos um ano, e por todo o tempo em que for usado. Depois de 6 meses sem visitas, mandamos um e-mail para você, e um mês depois ele é liberado.

Erros

Um corpo JSON com error, e detail quando há algo útil a acrescentar. Um arquivo que recusamos (uma chave deixada no arquivo, um tipo não suportado) é um 422 com o motivo em palavras, não um stack trace.