Backend API Reference

Backend API Reference

The Backend service exposes both anonymous account-lifecycle routes and authenticated admin or user routes.

Health

GET /health

Returns a simple health payload:

1
{ "status": "ok" }

Public Auth APIs

GET /auth/plans

Returns the public plan catalog and enterprise contact metadata.

Response shape:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
  "plans": [
    {
      "key": "starter",
      "name": "Starter",
      "isPaid": true,
      "limits": {
        "maxRecords": 10000,
        "maxKeyPlusValueBytes": 2048,
        "maxFiles": 1000,
        "maxFileSizeBytes": 1048576
      },
      "pricing": {
        "annualTotalUsd": 120,
        "monthlyUsd": 12.0
      }
    }
  ],
  "enterprise": {
    "key": "enterprise",
    "label": "Enterprise",
    "contact": "enquiry@hardencloud.com"
  }
}

POST /auth/orgadmin/register

Creates a pending org-admin registration and sends a verification email.

Request:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "orgName": "Acme Inc",
  "adminName": "Jane Admin",
  "email": "jane@example.com",
  "password": "CorrectHorseBatteryStaple1!",
  "countryCode": "US",
  "plan": "starter",
  "billingCycle": "monthly",
  "stripePaymentMethodId": "pm_card_visa"
}

Success response:

1
2
3
4
5
{
  "requiresVerification": true,
  "message": "Verification email sent. Please verify your email to complete registration.",
  "verificationToken": null
}

Behavior notes:

  • plan is required.
  • enterprise is not self-service and returns a contact message.
  • paid plans require a payment method during verification.
  • password must be at least 10 characters.
  • country availability is restricted to US, CA, GB, EU, CH, NO, IS, AL, AZ, AM, TR, MK, ME, AU, NZ, SG, MY, JP, and KR.
  • if email delivery is disabled, verificationToken is returned so non-production environments can continue the flow.

GET /auth/orgadmin/verify?token=<token>

Finalizes registration, optionally creates a Stripe subscription for paid plans, and returns the org-admin API key.

Response:

1
{ "apiKey": "<org-admin-api-key>" }

POST /auth/orgadmin/login

Signs in a verified org admin with email and password and returns a fresh API key.

Request:

1
2
3
4
{
  "email": "jane@example.com",
  "password": "CorrectHorseBatteryStaple1!"
}

Response:

1
{ "apiKey": "<org-admin-api-key>" }

Admin APIs

All admin routes require X-Api-Key.

POST /admin/orgs

Global-admin only. Creates a new organization.

Request:

1
{ "name": "acme" }

GET /admin/orgs

Global-admin only. Lists organizations.

POST /admin/orgs/{orgId}/users

Creates a user in an org.

Request:

1
2
3
4
5
6
{
  "name": "payments-service",
  "isAdmin": false,
  "publicKeyEccB64": null,
  "publicKeyKyberB64": null
}

Authorization behavior:

  • global admin can create only the first org admin in a target org
  • org admins can create additional org admins or regular users in their org

Response includes the plaintext API key in apiKeyHash.

GET /admin/orgs/{orgId}/users

Lists users in an org for a global admin or that org’s org admin.

POST /admin/orgs/{orgId}/users/{userId}/apikey/rotate

Rotates a user’s API key.

Response:

1
{ "apiKey": "<new-api-key>" }

GET /admin/orgs/{orgId}/storage

Reads the org’s S3-compatible file storage configuration.

Response:

1
2
3
4
5
6
7
8
{
  "serviceUrl": "https://s3.example.com",
  "bucket": "org-files",
  "accessKey": "AKIA...",
  "hasSecretKey": true,
  "forcePathStyle": true,
  "region": "us-east-1"
}

PUT /admin/orgs/{orgId}/storage

Creates or updates the org’s S3-compatible file storage configuration.

Request:

1
2
3
4
5
6
7
8
{
  "serviceUrl": "https://s3.example.com",
  "bucket": "org-files",
  "accessKey": "AKIA...",
  "secretKey": "secret...",
  "forcePathStyle": true,
  "region": "us-east-1"
}

Validation notes:

  • serviceUrl, bucket, and accessKey are required
  • serviceUrl must be an absolute URL
  • secretKey is required on first save

User APIs

All user routes require X-Api-Key.

GET /users/me

Returns the authenticated user record. The API key hash is blanked in the response.

POST /users/me/keys

Stores the authenticated user’s public keys and encrypted private keys.

Request:

1
2
3
4
5
6
{
  "publicKeyEccB64": "base64-ecc-public",
  "publicKeyKyberB64": "base64-kyber-public",
  "encryptedPrivateKeyEccB64": "base64-encrypted-ecc-private",
  "encryptedPrivateKeyKyberB64": "base64-encrypted-kyber-private"
}

GET /users/org

Returns org-scoped public profiles for all users in the same organization.

GET /users/org/{userId}

Returns one org-scoped public profile. Users outside the org return 404.

Recovery APIs

These routes support trusted-user recovery workflows.

PUT /users/me/recovery/trustees/{trusteeUserId}

Creates or updates a trusted-user recovery share.

Request:

1
2
3
4
5
6
{
  "encryptedPrivateKeyEccShareB64": "base64-share-ecc",
  "encryptedPrivateKeyKyberShareB64": "base64-share-kyber",
  "xorApplied": true,
  "xorSaltHint": "dog-name"
}

Validation notes:

  • you cannot assign yourself as a trustee
  • the trustee must exist in the same org
  • both share payloads must be valid base64

GET /users/me/recovery/trustees

Lists trustees configured by the current user.

DELETE /users/me/recovery/trustees/{trusteeUserId}

Removes a trusted-user recovery share.

GET /users/me/recovery/shares

Lists owners who have shared recovery material with the current user.

GET /users/me/recovery/shares/{ownerUserId}

Returns the stored recovery share for the current user as trustee.

POST /users/me/recovery/restore/{ownerUserId}

Lets a trusted user submit restored encrypted private keys for an owner.

Request:

1
2
3
4
5
6
{
  "encryptedPrivateKeyEccB64": "base64-restored-ecc",
  "encryptedPrivateKeyKyberB64": "base64-restored-kyber",
  "usedXor": true,
  "xorSaltHint": "dog-name"
}

Response:

1
{ "requiresRekey": true }

KV APIs

All KV routes require X-Api-Key.

PUT /kv/{key}

Stores encrypted secret metadata.

Request:

1
2
3
4
5
{
  "ciphertextB64": "base64-aes-gcm-payload",
  "encryptedAesKeyEccB64": "base64-ecc-wrap",
  "encryptedAesKeyKyberB64": "base64-kyber-wrap"
}

GET /kv/{key}

Returns the stored encrypted record.

DELETE /kv/{key}

Soft-deletes the key.

GET /kv

Lists active keys for the authenticated user.

File APIs

All file routes require X-Api-Key.

POST /files

Stores encrypted file metadata and uploads ciphertext to the configured object store.

Request:

1
2
3
4
5
6
7
{
  "encryptedFileNameB64": "base64-aes-gcm-filename",
  "ciphertextB64": "base64-aes-gcm-file-content",
  "encryptedAesKeyEccB64": "base64-ecc-wrap",
  "encryptedAesKeyKyberB64": "base64-kyber-wrap",
  "contentType": "application/json"
}

Validation notes:

  • free plan orgs cannot store files
  • the org must have file storage configured
  • file count and size are enforced by plan

GET /files

Lists file metadata for the current user.

GET /files/{id}

Returns encrypted file metadata plus ciphertext loaded from object storage.

DELETE /files/{id}

Soft-deletes the file record and attempts to delete the object from storage.

Audit API

GET /audit

Org-admin only. Returns KV audit entries for the org.

Each entry includes:

  • key
  • action as create, update, or delete
  • timestampUtc
  • version
  • userId

Plan Limits

Plan Max KV Records Max Key + Value Bytes Max Files Max File Size
Free 1,000 1,024 0 0
Starter 10,000 2,048 1,000 1 MiB
SMB 25,000 4,096 2,500 4 MiB
Business 100,000 8,192 10,000 8 MiB

Error Patterns

  • 400: validation failure, unsupported plan/country, missing storage config, plan limit reached
  • 401: missing or invalid API key
  • 403: caller is authenticated but lacks the required admin role
  • 404: org, user, key, file, or recovery share not found

Error payloads generally follow:

1
{ "error": "message" }