API

Deploy from CI or a script. Pages, domains and forms over HTTPS, with a token instead of a login.

Tokens

Create a token from the API tokens section of your account page. It is shown once, right after you create it — store it as a secret in your CI, and if you lose it, revoke it and make another.

A token acts as your account for pages, domains and forms. It cannot log in, create more tokens or change two-factor; those stay in the dashboard. The account page shows when each token was last used, so a stale one is easy to spot and revoke.

Send it as a bearer token to https://api.majinode.com:

Check the token works
$ curl -H "Authorization: Bearer $MAJINODE_TOKEN" https://api.majinode.com/auth/me

Deploy a Page

Create the page once, from the dashboard or with the API:

$ curl -H "Authorization: Bearer $MAJINODE_TOKEN" -H "Content-Type: application/json" -d '{"name":"my-site"}' https://api.majinode.com/pages

Then upload a .zip, .tar or .tar.gz of your build output. Each upload replaces everything the page served before. If the archive wraps everything in one top-level directory, its contents are served from the root. Archives over 64 MiB are rejected with a 413.

Upload a build

The response lists every file that was extracted.
$ zip -r dist.zip dist && curl --fail-with-body -H "Authorization: Bearer $MAJINODE_TOKEN" -F file=@dist.zip https://api.majinode.com/pages/my-site/upload

--fail-with-body makes curl exit non-zero on an error, so a failed deploy fails the job rather than passing silently.

GitHub Actions

Add the token as a repository secret named MAJINODE_TOKEN, then deploy after your build step:

- name: Deploy to majinode
  run: |
    zip -r dist.zip dist
    curl --fail-with-body \
      -H "Authorization: Bearer ${{ secrets.MAJINODE_TOKEN }}" \
      -F file=@dist.zip \
      https://api.majinode.com/pages/my-site/upload

Endpoints

Requests and responses are JSON, except the upload, which takes a multipart file. Errors come back with a detail explaining what went wrong.

MethodPathWhat it does
GET/auth/meThe account the token belongs to
GET/pagesList your pages
POST/pagesCreate a page: {"name": "my-site"}
GET/pages/{name}Page detail, including its files
POST/pages/{name}/uploadReplace the page’s files with an archive
GET/pages/{name}/logsRecent requests to the page
DELETE/pages/{name}Delete the page, its files and its domains
GET/pages/{name}/domainsList custom domains
POST/pages/{name}/domainsClaim a domain: {"domain": "mysite.com"}
POST/pages/{name}/domains/{domain}/verifyCheck the TXT record and go live
DELETE/pages/{name}/domains/{domain}Remove a domain
GET/formsList your forms
POST/formsCreate a form: {"name": "Contact", "notify": true}
GET/forms/{id}/submissionsNewest first, ?limit= (up to 100) and &offset=
DELETE/forms/{id}Delete a form and its submissions