Skip to content
Hermida / Developer vaultUTC 07:01:07
Clearance · publicDeveloper portal

Build on the Hermida platform.

Hermida holds the live record of projects, services, and billing. These are the same APIs our own client workspace runs on — authenticate with a token, call a function, get scoped JSON back.

01
Transport
HTTPS, JSON in and JSON out
02
Auth
Bearer token, scoped to the member
03
Surface
Backend functions behind /functions
04
Money
Integer cents, ISO dates
curl · sample request
curl -X POST "$HERMIDA_API/functions/clientProjects" \  -H "Authorization: Bearer $HERMIDA_TOKEN" \  -H "Content-Type: application/json" \  -d '{"action":"list","slug":"acme-co"}'
01Procedure

From a token to your first integration.

Three steps. No SDK required — the API is plain HTTPS and JSON, so it works from a script, a server, or a spreadsheet automation.

  1. Step 01

    Issue a personal access token

    Open your workspace settings, then Secrets → Personal access tokens, and create a token for the integration. It is shown once. Revoke it there the moment a machine stops using it.

    header
    Authorization: Bearer hmd_live_…
  2. Step 02

    Call a function

    Every endpoint is a POST to /functions/<name> with a JSON body. The action in the body selects the behaviour of that function.

    curl
    curl -X POST "$HERMIDA_API/functions/clientProjects" \  -H "Authorization: Bearer $HERMIDA_TOKEN" \  -H "Content-Type: application/json" \  -d '{"action":"list","slug":"acme-co"}'
  3. Step 03

    Read the scoped response

    Responses are JSON with an ok flag. A failure returns ok: false plus a code you can branch on — never a partial payload.

    javascript
    const res = await fetch(`${BASE}/functions/clientProjects`, {  method: 'POST',  headers: {    Authorization: `Bearer ${process.env.HERMIDA_TOKEN}`,    'Content-Type': 'application/json',  },  body: JSON.stringify({ action: 'list', slug: 'acme-co' }),}); const { ok, projects, code } = await res.json();if (!ok) throw new Error(code);
02Authentication

A bearer token, and the permissions already attached to it.

Hermida has no separate permission model for integrations. The token inherits the member, the member inherits their memberships, and the API enforces both on every request.

A personal access token runs as the person who created it. It sees exactly the organizations, projects, files, and invoices that membership already grants — nothing wider, and nothing across organizations.

  • Projects

    Read a project with its milestones, tasks, and published updates, or mark a client-visible task complete.

  • Services

    Browse the self-service catalog, then add services to a project — the batch becomes one invoice.

  • Billing

    The organization statement: outstanding, overdue, paid year-to-date, invoices, payments, and services.

  • Files

    Client-visible files, version metadata, and signed download URLs that expire in five minutes.

request
curl -X POST "$HERMIDA_API/functions/clientProjects" \  -H "Authorization: Bearer $HERMIDA_TOKEN" \  -H "Content-Type: application/json" \  -d '{"action":"billing","slug":"acme-co"}'
typescript
const res = await fetch(`${BASE}/functions/clientProjects`, {  method: 'POST',  headers: {    Authorization: `Bearer ${process.env.HERMIDA_TOKEN}`,    'Content-Type': 'application/json',  },  body: JSON.stringify({ action: 'billing', slug: 'acme-co' }),}); const { ok, billing } = await res.json();if (!ok) throw new Error('request_failed');

Create a token in your workspace under Settings → Secrets → Personal access tokens, or from the API page. It is shown once; revoke it there and access ends immediately.

03Reference

Six functions behind every workspace screen.

Each endpoint takes a JSON body with an action. Responses are scoped to the token's member, and failures come back as ok: false with a code — never a partial payload.

POST/functions/clientProjectsid · client-projects

Projects, dashboard figures, and the billing statement.

Returns the projects the signed-in member can access, one project with its milestones, tasks, and updates, the workspace dashboard figures, or the organization's billing statement. Every response is narrowed to that member's membership — there is no cross-organization read.

Parameters

actionrequired
string — dashboard · billing · list · get · complete-task
slugrequired
string — Organization slug.
project_slug
string — Required for get and complete-task.
task_id
string — complete-task only.
request body
{  "action": "list",  "slug": "acme-co"}
response
{  "ok": true,  "projects": [    {      "id": "6ae25c21df4d4eed49b7444a",      "project_code": "HT-2026-0006",      "name": "Dispatch console",      "summary": "Real-time dispatch for a regional freight broker.",      "status": "active",      "target_end_date": "2026-11-30",      "latest_update_at": "2026-10-24T14:02:00.000Z",      "progress": 42    }  ],  "total": 1}

noteThe billing action returns outstanding, overdue, paid year-to-date, invoices, payments, and services. All money is integer cents.

04Failure modes

One shape for every failure.

A failed request returns a JSON body with ok: false and a stable code, plus an HTTP status you can branch on. Nothing partial is ever written.

  • invalid_action400

    The action is missing or not one this endpoint accepts.

  • access_denied403

    No active membership grants access, or the record belongs to another organization.

  • membership_suspended403

    The membership exists but is suspended. An organization admin can restore it.

  • organization_suspended403

    The organization is suspended or archived.

  • not_found404

    The requested record does not exist.

  • rate_limited429

    Too many requests from this token. Back off and retry after the Retry-After header.

  • server_error500

    The request failed on our side. Safe to retry with backoff; contact us if it persists.

403 forbidden
{  "ok": false,  "code": "access_denied"}

Requests are rate limited per token. On a 429, back off exponentially and honour the Retry-After header. Retry 5xx responses with backoff; never retry a 4xx unchanged.

05Distribution

Ambient OS, and anything else we ship.

Installers distributed directly by Hermida. Ambient OS is the corporate build for our own servers and office machines — download it here, then follow the install note your account contact sent.

› 1 package available

  • Ambient OS

    macOS · 413 KB · AmbientOSapp.zip

    The Ambient OS build for Hermida corporate servers and office machines.

06Revision log

What changed, and when.

Platform releases that affect the API surface. Additive changes ship without a breaking note; anything that can break an integration is called out here first.

  1. 2026.10

    October 2026

    Self-service services

    • projectServices assign issues one invoice for a whole batch of services.
    • A project without its own billing account now inherits the organization's account.
    • Every service request writes client-visible activity against the project.
  2. 2026.09

    September 2026

    Files and notifications

    • clientFiles: signed downloads, version metadata, and approval state.
    • myNotifications: unread counts and read controls for members.
  3. 2026.08

    August 2026

    Hermida ID

    • One account across organizations, with a primary organization and per-organization roles.
    • myAccount context returns every membership in a single call.
  4. 2026.07

    July 2026

    Billing Center

    • Invoices, payments, credits, and adjustments as first-class records.
    • Organization statements built from project-linked invoices.

07 / Next step

Need an integration built instead?

If the work is connecting Hermida to a system you already run, our team builds and maintains that integration — scoped, documented, and handed over.

Talk to engineering
All requests loggedTLS 1.3 onlyTokens scoped to memberInteger centsISO 8601 datesRate limited per tokenNo partial writesDocs ship with the releaseAll requests loggedTLS 1.3 onlyTokens scoped to memberInteger centsISO 8601 datesRate limited per tokenNo partial writesDocs ship with the release

We use optional analytics to understand how this website is used. No analytics loads until you allow it, and declining keeps everything on the site working.