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.
Atualizar sem quebrar o link
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, é um402comcode: "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 é um422comslug_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}/maintorna um deles o endereço principal, eDELETE …/addresses/{slug}o transforma num endereço antigo. Recusado comneeds_pro_extra_address,extra_address_limit,needs_pro_short_address,short_address_limit,slug_brandouslug_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.

