Tout ce que fait le tableau de bord, depuis ton terminal
Une clé de compte. Liste tes sites, déploie dessus, renomme-les, lis ce que tes formulaires ont récolté, supprime-les — en HTTP tout simple, depuis un script, un job de CI ou un agent.
Trois commandes
Crée une clé sur ton tableau de bord, vérifie qu'elle marche, et mets un dossier en ligne. La clé va dans un en-tête Authorization à chaque appel.
curl -H "Authorization: Bearer hvs_…" https://harvis.dev/api/v1
curl -H "Authorization: Bearer hvs_…" https://harvis.dev/api/v1/sites
curl -X POST https://harvis.dev/api/v1/sites \ -H "Authorization: Bearer hvs_…" \ -F "files=@index.html" -F "paths=index.html"
L'app web et l'API ne peuvent pas diverger
Chaque capacité est déclarée une fois, dans un seul fichier, et le tableau de bord comme cette API sont construits à partir de là. openapi.json est généré depuis cette déclaration, et le build échoue si les deux divergent. Ce n'est donc pas une documentation qui décrit le produit — c'est ce dont le produit est fait.
- Une implémentation par capacité, appelée par l'app web comme par ton script.
- openapi.json est généré, jamais écrit à la main, et servi sur /openapi.json.
- Un build échoue dès qu'une route, le contrat et le document cessent de concorder.
Avec une clé, le site est à toi immédiatement
Déployer sans compte marche toujours et marchera toujours — tu reçois un lien de revendication privé à ouvrir plus tard. Envoie une clé sur le même appel et il n'y a rien à revendiquer : le site est sur ton compte dès le premier octet, et il n'expire jamais.
zip -r site.zip . && curl -X POST https://harvis.dev/api/upload \ -H "Authorization: Bearer hvs_…" \ -H "Content-Type: application/zip" --data-binary @site.zip
Toute la surface
Les formes complètes des requêtes et des réponses sont dans le document OpenAPI.
| méthode | chemin | ce qu'il fait |
|---|---|---|
| GET | /api/v1 | Check that a credential works. |
| GET | /api/v1/keys | The account's API keys. Revoked keys are not listed. |
| POST | /api/v1/keys | Create an API key. |
| DELETE | /api/v1/keys/{keyId} | Revoke an API key. Anything using it stops working immediately. |
| GET | /api/v1/me | The account a credential belongs to. |
| GET | /api/v1/sites | List the account's sites, newest first. |
| POST | /api/v1/sites | Create a site from a folder of files. |
| DELETE | /api/v1/sites/{id} | Delete a site, its files and its form submissions. |
| GET | /api/v1/sites/{id} | One site. |
| PATCH | /api/v1/sites/{id} | Rename a site, change its web address, or both. |
| POST | /api/v1/sites/{id}/deploy | Replace every file of a site with the uploaded set. |
| POST | /api/v1/sites/{id}/deploy-token | Issue a new deploy token for a site. The old one stops working immediately. |
| POST | /api/v1/sites/{id}/deploy/zip | Replace every file of a site from a zip archive sent as the raw request body. |
| GET | /api/v1/sites/{id}/files | Every file a site is serving. |
| POST | /api/v1/sites/{id}/files | Add or overwrite individual files, leaving the rest of the site alone. |
| DELETE | /api/v1/sites/{id}/submissions | Delete every submission for a site, or every one of a single form. |
| GET | /api/v1/sites/{id}/submissions | One page of a site's form submissions, newest first. |
| DELETE | /api/v1/sites/{id}/submissions/{submissionId} | Delete one submission. |
| GET | /api/v1/sites/{id}/submissions/{submissionId} | One submission. |
| GET | /api/v1/sites/{id}/submissions/csv | Export a site's form submissions as CSV. |
| POST | /api/v1/sites/{id}/submissions/read | Mark every unread submission as read. |
| GET | /api/v1/sites/{id}/submissions/summary | How many submissions a site holds, how many are unread, and which forms exist. |
| POST | /api/v1/sites/import | Create a site by downloading a single page from a known artifact URL. |
Chaque échec a la même forme
Branche sur le code, jamais sur le message. Les codes sont stables ; la prose est pour celui qui lit le log.
{
"error": {
"code": "subdomainTaken",
"message": "That address is already taken. Try another."
}
}