NoPeek owl logoNoPeek Docs

API Reference

# NoPeek — E2EE chat APIs your servers can't read.

Every channel is end-to-end encrypted by default using MLS (RFC 9420). NoPeek servers act as an MLS delivery service: they store, order, and fan out opaque ciphertext. The only readable fields are routing metadata (sender id, channel id, timestamps, MLS epoch) — documented per endpoint.

## Authentication Three credential classes, all sent as Authorization: Bearer <secret>: - Org admin key (npk_live_…/npk_test_…, role org_admin) — org and app management. Dashboard/self-service only. Never ship to a server that handles chat traffic, never to a client. - App server key (role app_server) — your backend uses this for user provisioning, channel administration, moderation, webhooks, exports. - Session token — short-lived per-end-user token your backend mints via POST /v1/apps/{appId}/users/{userId}/sessions, then hands to the client SDK. All client endpoints and the WebSocket use this.

## Environments Apps are live or test. Test-key traffic against live apps (and vice versa) fails with WRONG_ENVIRONMENT.

## E2EE rules - Channel types default e2ee: true. Opt-out is explicit, only at type-creation, and badged in the dashboard forever. - In E2EE channels, message.ciphertext is required and plaintext is rejected (E2EE_REQUIRED inverse); in opted-out channels the reverse. - Server-side content features (profanity filter, plaintext search, server-rendered link previews) exist ONLY for opted-out channel types.

API version 2026-07-01 · OpenAPI 3.1.0 · 83 operations

Examples use https://api.nopeekapi.com. The base URL of the current deployment is injected at deploy time via config.js (window.NOPEEK_API_URL); when set, the URLs on this page update automatically.

Orgs

Self-service signup and org management.

POST /v1/orgs No authentication

Sign up (create an org)

Self-service signup. Returns the org plus a one-time org_admin API key secret. Provisioning is instant — an org/app is data, not infrastructure.

Request body

  • name string required
    Max length 200.
  • billingEmail string (email) required
  • password string required
    Max length 200.

Responses

201 Org created.
  • org Org
    • orgId string
    • name string
    • billingEmail string
    • plan string
      One of: free, starter, pro, enterprise.
    • hipaaBaaSignedAt string (date-time) | null
    • createdAt string (date-time)
  • apiKey ApiKeyWithSecret
    • apiKeyId string
    • role string
      One of: org_admin, app_server.
    • secretPrefix string
      First characters for display: npk_live_ab…
    • label string
    • lastUsedAt string (date-time) | null
    • createdAt string (date-time)
    • secret string
      Shown exactly once. Store it now.
409 Conflict (ALREADY_EXISTS, STALE_EPOCH, NO_KEY_PACKAGES…). Error
  • error object
    • code string
    • message string
cURL
curl -X POST "https://api.nopeekapi.com/v1/orgs" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Inc.",
    "billingEmail": "founders@acme.dev",
    "password": "correct-horse-battery-st4ple"
  }'
GET /v1/orgs/me Org admin key

Get the authenticated org

Responses

200 The org owning the presented key. Org
  • orgId string
  • name string
  • billingEmail string
  • plan string
    One of: free, starter, pro, enterprise.
  • hipaaBaaSignedAt string (date-time) | null
  • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/orgs/me" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY"

Apps

Applications — one per product/environment; instant provisioning.

GET /v1/apps Org admin key

List apps

Responses

200 Apps in this org.
  • apps array of App
    • appId string
    • orgId string
    • name string
    • environment string
      One of: live, test.
    • region string
    • webhookUrl string | null
    • webhookEvents array of string
    • createdAt string (date-time)
    • branding object | null
      White-label branding (logo URL + colors). Readable by clients via GET /branding.
    • sessionTtlSeconds integer
      Auto-logoff: session token lifetime. One of the allowed presets. One of: 172800, 604800, 2592000, 5184000, 7776000, 15552000.
    • appPolicy AppPolicy
      Capacitor remote-load force-update policy. Clients poll GET /v1/app-config every ~30s; a change in refreshToken (or a min-version gate the running build fails) triggers the update prompt.
      • forceRefreshEnabled boolean
      • refreshToken string
        Opaque token; when it changes, running clients reload.
      • minWebBuild string | null
      • minIosVersion string | null
      • minAndroidVersion string | null
      • title string
      • message string
      • iosUpdateUrl string | null
      • androidUpdateUrl string | null
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY"
POST /v1/apps Org admin key

Create an app

Requires an org_admin key. Also mints the app's first app_server key (returned once) and creates default channel types: direct, group, broadcast — all e2ee: true.

Request body

  • name string required
    Max length 200.
  • environment string required
    One of: live, test.
  • region string
    Default "us-east-1".

Responses

201 App created with defaults.
  • app App
    • appId string
    • orgId string
    • name string
    • environment string
      One of: live, test.
    • region string
    • webhookUrl string | null
    • webhookEvents array of string
    • createdAt string (date-time)
    • branding object | null
      White-label branding (logo URL + colors). Readable by clients via GET /branding.
    • sessionTtlSeconds integer
      Auto-logoff: session token lifetime. One of the allowed presets. One of: 172800, 604800, 2592000, 5184000, 7776000, 15552000.
    • appPolicy AppPolicy
      Capacitor remote-load force-update policy. Clients poll GET /v1/app-config every ~30s; a change in refreshToken (or a min-version gate the running build fails) triggers the update prompt.
      • forceRefreshEnabled boolean
      • refreshToken string
        Opaque token; when it changes, running clients reload.
      • minWebBuild string | null
      • minIosVersion string | null
      • minAndroidVersion string | null
      • title string
      • message string
      • iosUpdateUrl string | null
      • androidUpdateUrl string | null
  • serverKey ApiKeyWithSecret
    • apiKeyId string
    • role string
      One of: org_admin, app_server.
    • secretPrefix string
      First characters for display: npk_live_ab…
    • label string
    • lastUsedAt string (date-time) | null
    • createdAt string (date-time)
    • secret string
      Shown exactly once. Store it now.
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Chat (test)",
    "environment": "test",
    "region": "us-east-1"
  }'
GET /v1/apps/{appId} App server key

Get an app

Parameters

NameInTypeRequiredNotes
appId path string yes

Responses

200 The app. App
  • appId string
  • orgId string
  • name string
  • environment string
    One of: live, test.
  • region string
  • webhookUrl string | null
  • webhookEvents array of string
  • createdAt string (date-time)
  • branding object | null
    White-label branding (logo URL + colors). Readable by clients via GET /branding.
  • sessionTtlSeconds integer
    Auto-logoff: session token lifetime. One of the allowed presets. One of: 172800, 604800, 2592000, 5184000, 7776000, 15552000.
  • appPolicy AppPolicy
    Capacitor remote-load force-update policy. Clients poll GET /v1/app-config every ~30s; a change in refreshToken (or a min-version gate the running build fails) triggers the update prompt.
    • forceRefreshEnabled boolean
    • refreshToken string
      Opaque token; when it changes, running clients reload.
    • minWebBuild string | null
    • minIosVersion string | null
    • minAndroidVersion string | null
    • title string
    • message string
    • iosUpdateUrl string | null
    • androidUpdateUrl string | null
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
PATCH /v1/apps/{appId} App server key

Update app settings (name, webhook, push config)

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body (optional)

  • name string
  • webhookUrl string (uri) | null
  • webhookEvents array of string
    e.g. ["message.new", "member.joined"]. Webhook payloads for E2EE channels contain metadata only.
  • branding object | null
    White-label branding blob (logo URL + brand colors only).
  • appPolicy object | null
    Per-app force-update policy overlay, merged over the global policy.
  • sessionTtlSeconds integer
    Auto-logoff preset in seconds: 48h, 7d, 30d, 60d, 90d, 180d. Any other value → INVALID_REQUEST. One of: 172800, 604800, 2592000, 5184000, 7776000, 15552000.

Responses

200 Updated app. App
  • appId string
  • orgId string
  • name string
  • environment string
    One of: live, test.
  • region string
  • webhookUrl string | null
  • webhookEvents array of string
  • createdAt string (date-time)
  • branding object | null
    White-label branding (logo URL + colors). Readable by clients via GET /branding.
  • sessionTtlSeconds integer
    Auto-logoff: session token lifetime. One of the allowed presets. One of: 172800, 604800, 2592000, 5184000, 7776000, 15552000.
  • appPolicy AppPolicy
    Capacitor remote-load force-update policy. Clients poll GET /v1/app-config every ~30s; a change in refreshToken (or a min-version gate the running build fails) triggers the update prompt.
    • forceRefreshEnabled boolean
    • refreshToken string
      Opaque token; when it changes, running clients reload.
    • minWebBuild string | null
    • minIosVersion string | null
    • minAndroidVersion string | null
    • title string
    • message string
    • iosUpdateUrl string | null
    • androidUpdateUrl string | null
cURL
curl -X PATCH "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "webhookUrl": "https://example.com/hooks/nopeek",
    "webhookEvents": [
      "message.new",
      "member.joined",
      "report.created"
    ]
  }'
JavaScript (fetch)
const res = await fetch('https://api.nopeekapi.com/v1/apps/app_7f3kq2c9', {
  method: 'PATCH',
  headers: {
    Authorization: 'Bearer npk_live_SERVER_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "webhookUrl": "https://example.com/hooks/nopeek",
    "webhookEvents": [
      "message.new",
      "member.joined",
      "report.created"
    ]
  }),
});
const data = await res.json();
DELETE /v1/apps/{appId} Org admin key

Delete an app and all its data

Parameters

NameInTypeRequiredNotes
appId path string yes

Responses

204 Deleted.
cURL
curl -X DELETE "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY"

API Keys

GET /v1/apps/{appId}/keys Org admin key

List keys (prefixes only)

Parameters

NameInTypeRequiredNotes
appId path string yes

Responses

200 Keys.
  • keys array of ApiKey
    • apiKeyId string
    • role string
      One of: org_admin, app_server.
    • secretPrefix string
      First characters for display: npk_live_ab…
    • label string
    • lastUsedAt string (date-time) | null
    • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/keys" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY"
POST /v1/apps/{appId}/keys Org admin key

Mint an app server key

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body (optional)

  • label string
    Max length 120.

Responses

201 Key created; secret shown once. ApiKeyWithSecret
  • apiKeyId string
  • role string
    One of: org_admin, app_server.
  • secretPrefix string
    First characters for display: npk_live_ab…
  • label string
  • lastUsedAt string (date-time) | null
  • createdAt string (date-time)
  • secret string
    Shown exactly once. Store it now.
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/keys" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "backend-primary"
  }'
DELETE /v1/apps/{appId}/keys/{apiKeyId} Org admin key

Revoke a key

Parameters

NameInTypeRequiredNotes
appId path string yes
apiKeyId path string yes

Responses

204 Revoked.
cURL
curl -X DELETE "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/keys/key_3j7h9cx1" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY"

Users

GET /v1/apps/{appId}/users App server key

List users

Parameters

NameInTypeRequiredNotes
appId path string yes
limit query integer no Default 50. Min 1. Max 200.
cursor query string no

Responses

200 Page of users.
  • users array of User
    • userId string
    • appId string
    • externalId string
    • nickname string
    • profileUrl string | null
    • metadata object
      • <key> string
    • isActive boolean
    • lastSeenAt string (date-time) | null
    • createdAt string (date-time)
  • nextCursor string | null
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users?limit=50" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
POST /v1/apps/{appId}/users App server key

Create (or upsert by externalId) a user

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • externalId string required
    Max length 255.
  • nickname string
    Max length 80.
  • profileUrl string (uri) | null
  • metadata object
    • <key> string

Responses

201 User. User
  • userId string
  • appId string
  • externalId string
  • nickname string
  • profileUrl string | null
  • metadata object
    • <key> string
  • isActive boolean
  • lastSeenAt string (date-time) | null
  • createdAt string (date-time)
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "user-1001",
    "nickname": "Amina",
    "metadata": {
      "team": "support"
    }
  }'
JavaScript (fetch)
const res = await fetch('https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer npk_live_SERVER_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "externalId": "user-1001",
    "nickname": "Amina",
    "metadata": {
      "team": "support"
    }
  }),
});
const data = await res.json();
GET /v1/apps/{appId}/users/{userId} App server key

Get a user

Parameters

NameInTypeRequiredNotes
appId path string yes
userId path string yes

Responses

200 User. User
  • userId string
  • appId string
  • externalId string
  • nickname string
  • profileUrl string | null
  • metadata object
    • <key> string
  • isActive boolean
  • lastSeenAt string (date-time) | null
  • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
PATCH /v1/apps/{appId}/users/{userId} App server key

Update a user

Parameters

NameInTypeRequiredNotes
appId path string yes
userId path string yes

Request body (optional)

  • nickname string
  • profileUrl string | null
  • metadata object
    • <key> string
  • isActive boolean

Responses

200 Updated user. User
  • userId string
  • appId string
  • externalId string
  • nickname string
  • profileUrl string | null
  • metadata object
    • <key> string
  • isActive boolean
  • lastSeenAt string (date-time) | null
  • createdAt string (date-time)
cURL
curl -X PATCH "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "nickname": "Amina B.",
    "isActive": true
  }'
DELETE /v1/apps/{appId}/users/{userId} App server key

Delete a user (GDPR/right-to-erasure)

Parameters

NameInTypeRequiredNotes
appId path string yes
userId path string yes

Responses

204 Deleted.
cURL
curl -X DELETE "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"

Sessions

POST /v1/apps/{appId}/users/{userId}/sessions App server key

Mint a client session token

Your backend calls this, then hands the token to your client app. Default TTL 24h.

Parameters

NameInTypeRequiredNotes
appId path string yes
userId path string yes

Request body (optional)

  • ttlSeconds integer
    Default 86400. Min 60. Max 2592000.

Responses

201 Session token (shown once).
  • sessionToken string
  • expiresAt string (date-time)
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4/sessions" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ttlSeconds": 86400
  }'
JavaScript (fetch)
const res = await fetch('https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4/sessions', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer npk_live_SERVER_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "ttlSeconds": 86400
  }),
});
const data = await res.json();

Devices

Per-user devices; each holds its own MLS credential.

GET /v1/apps/{appId}/users/{userId}/devices App server key

List a user's devices

Parameters

NameInTypeRequiredNotes
appId path string yes
userId path string yes

Responses

200 Devices.
  • devices array of Device
    • deviceId string
    • userId string
    • credentialKey string (base64)
    • platform string
      One of: web, ios, android, desktop, server.
    • displayName string
    • revokedAt string (date-time) | null
    • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4/devices" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
POST /v1/apps/{appId}/users/{userId}/devices Session token

Register a device (client)

Client-authenticated. Registers this device's MLS signature credential.

Parameters

NameInTypeRequiredNotes
appId path string yes
userId path string yes

Request body

  • credentialKey string (base64) required
    Ed25519 public key, base64.
  • platform string required
    One of: web, ios, android, desktop, server.
  • displayName string
    Max length 120.
  • pushToken string | null
  • pushProvider string | null
    One of: apns, fcm.

Responses

201 Device. Device
  • deviceId string
  • userId string
  • credentialKey string (base64)
  • platform string
    One of: web, ios, android, desktop, server.
  • displayName string
  • revokedAt string (date-time) | null
  • createdAt string (date-time)
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4/devices" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "credentialKey": "ZWQyNTUxOVB1YmxpY0tleQ==",
    "platform": "web",
    "displayName": "Amina’s laptop"
  }'
JavaScript (fetch)
const res = await fetch('https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4/devices', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer nps_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "credentialKey": "ZWQyNTUxOVB1YmxpY0tleQ==",
    "platform": "web",
    "displayName": "Amina’s laptop"
  }),
});
const data = await res.json();
DELETE /v1/apps/{appId}/users/{userId}/devices/{deviceId} App server key

Revoke a device

Peers receive member.updated MLS proposals to remove this device from groups at next commit.

Parameters

NameInTypeRequiredNotes
appId path string yes
userId path string yes
deviceId path string yes

Responses

204 Revoked.
cURL
curl -X DELETE "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4/devices/dev_5r8s2mv6" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"

Key Registry

MLS key packages — publish, count, claim. All payloads opaque.

GET /v1/apps/{appId}/users/{userId}/devices/{deviceId}/key-packages Session token

Count unclaimed key packages (client)

Parameters

NameInTypeRequiredNotes
appId path string yes
userId path string yes
deviceId path string yes

Responses

200 Pool size.
  • available integer
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4/devices/dev_5r8s2mv6/key-packages" \
  -H "Authorization: Bearer nps_SESSION_TOKEN"
POST /v1/apps/{appId}/users/{userId}/devices/{deviceId}/key-packages Session token

Publish MLS key packages (client)

Devices keep a pool (recommend ≥ 20) of single-use key packages. Payloads are opaque to NoPeek.

Parameters

NameInTypeRequiredNotes
appId path string yes
userId path string yes
deviceId path string yes

Request body

  • keyPackages array of object required
    Max items 100.
    • cipherSuite integer required
    • data string (base64) required
    • dataHash string required
    • expiresAt string (date-time) required

Responses

201 Count now available.
  • available integer
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4/devices/dev_5r8s2mv6/key-packages" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "keyPackages": [
      {
        "cipherSuite": 1,
        "data": "a2V5UGFja2FnZUJsb2I=",
        "dataHash": "sha256:9f2b1c44",
        "expiresAt": "2026-10-01T00:00:00Z"
      }
    ]
  }'
POST /v1/apps/{appId}/users/{userId}/key-packages/claim Session token

Claim one key package per device of a user (client)

Called when adding userId to an E2EE channel. Atomically claims one unclaimed package per active device (each package is single-use). NO_KEY_PACKAGES if any device's pool is empty.

Parameters

NameInTypeRequiredNotes
appId path string yes
userId path string yes

Responses

200 One package per device.
  • keyPackages array of KeyPackage
    • keyPackageId string
    • userId string
    • deviceId string
    • cipherSuite integer
    • data string (base64)
      Opaque TLS-serialized MLS KeyPackage.
    • dataHash string
    • expiresAt string (date-time)
409 Conflict (ALREADY_EXISTS, STALE_EPOCH, NO_KEY_PACKAGES…). Error
  • error object
    • code string
    • message string
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4/key-packages/claim" \
  -H "Authorization: Bearer nps_SESSION_TOKEN"
JavaScript (fetch)
const res = await fetch('https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4/key-packages/claim', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer nps_SESSION_TOKEN',
  },
});
const data = await res.json();

MLS Groups

Delivery-service endpoints for MLS handshake traffic.

GET /v1/apps/{appId}/mls/groups/{mlsGroupId}/handshakes Session token

Fetch handshake backlog since an epoch (client catch-up)

Parameters

NameInTypeRequiredNotes
appId path string yes
mlsGroupId path string yes
sinceEpoch query integer no Min 0.

Responses

200 Ordered handshake messages.
  • handshakes array of HandshakeMessage
    • mlsGroupId string required
    • epoch integer required
    • kind string required
      One of: proposal, commit, welcome, group_info.
    • senderDeviceId string
    • recipientDeviceIds array of string
      Welcome routing only.
    • payload string (base64) required
      Opaque to NoPeek.
    • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/mls/groups/mlsg_2v6b8nt3/handshakes?sinceEpoch=41" \
  -H "Authorization: Bearer nps_SESSION_TOKEN"
POST /v1/apps/{appId}/mls/groups/{mlsGroupId}/handshakes Session token

Submit MLS handshake traffic (client)

Commits are accepted only at the group's current epoch (single-writer rule); on success the epoch increments and the blob fans out to member devices over WS. Welcomes route only to recipientDeviceIds. Rejected commits return STALE_EPOCH.

Parameters

NameInTypeRequiredNotes
appId path string yes
mlsGroupId path string yes

Request body HandshakeMessage

  • mlsGroupId string required
  • epoch integer required
  • kind string required
    One of: proposal, commit, welcome, group_info.
  • senderDeviceId string
  • recipientDeviceIds array of string
    Welcome routing only.
  • payload string (base64) required
    Opaque to NoPeek.
  • createdAt string (date-time)

Responses

202 Accepted and fanned out.
409 Conflict (ALREADY_EXISTS, STALE_EPOCH, NO_KEY_PACKAGES…). Error
  • error object
    • code string
    • message string
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/mls/groups/mlsg_2v6b8nt3/handshakes" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mlsGroupId": "mlsg_2v6b8nt3",
    "epoch": 42,
    "kind": "commit",
    "senderDeviceId": "dev_5r8s2mv6",
    "payload": "bWxzLWhhbmRzaGFrZS1ibG9i"
  }'

Channel Types

GET /v1/apps/{appId}/channel-types App server key

List channel types

Parameters

NameInTypeRequiredNotes
appId path string yes

Responses

200 Types.
  • channelTypes array of ChannelType
    • key string required
      Pattern ^[a-z0-9_-]{1,64}$.
    • name string required
    • kind string required
      One of: direct, group, broadcast.
    • e2ee boolean
      Default true.
    • editWindowSeconds integer | null
    • recallWindowSeconds integer | null
    • readReceipts boolean
      Default true.
    • typingIndicators boolean
      Default true.
    • reactions boolean
      Default true.
    • threads boolean
      Default true.
    • profanityFilter boolean
      Opted-out (e2ee=false) types only. Default false.
    • maxMembers integer
      Default 100.
    • channelTypeId string
    • appId string
    • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channel-types" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
POST /v1/apps/{appId}/channel-types App server key

Create a channel type

e2ee defaults to true. Setting e2ee: false is the ONLY way any message plaintext ever reaches NoPeek, is allowed only at creation time, and is surfaced with a permanent badge in the dashboard.

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body ChannelTypeCreate

  • key string required
    Pattern ^[a-z0-9_-]{1,64}$.
  • name string required
  • kind string required
    One of: direct, group, broadcast.
  • e2ee boolean
    Default true.
  • editWindowSeconds integer | null
  • recallWindowSeconds integer | null
  • readReceipts boolean
    Default true.
  • typingIndicators boolean
    Default true.
  • reactions boolean
    Default true.
  • threads boolean
    Default true.
  • profanityFilter boolean
    Opted-out (e2ee=false) types only. Default false.
  • maxMembers integer
    Default 100.

Responses

201 Channel type. ChannelType
  • key string required
    Pattern ^[a-z0-9_-]{1,64}$.
  • name string required
  • kind string required
    One of: direct, group, broadcast.
  • e2ee boolean
    Default true.
  • editWindowSeconds integer | null
  • recallWindowSeconds integer | null
  • readReceipts boolean
    Default true.
  • typingIndicators boolean
    Default true.
  • reactions boolean
    Default true.
  • threads boolean
    Default true.
  • profanityFilter boolean
    Opted-out (e2ee=false) types only. Default false.
  • maxMembers integer
    Default 100.
  • channelTypeId string
  • appId string
  • createdAt string (date-time)
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channel-types" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "support_dm",
    "name": "Support DM",
    "kind": "direct",
    "editWindowSeconds": 900,
    "recallWindowSeconds": 3600
  }'

Channels

GET /v1/apps/{appId}/channels App server key

List channels (server key) / my channels (session token)

Parameters

NameInTypeRequiredNotes
appId path string yes
limit query integer no Default 50. Min 1. Max 200.
cursor query string no

Responses

200 Page of channels.
  • channels array of Channel
    • channelId string
    • appId string
    • channelTypeKey string
    • kind string
      One of: direct, group, broadcast.
    • e2ee boolean
    • name string
    • coverUrl string | null
    • metadata object
      • <key> string
    • isFrozen boolean
    • mlsGroupId string | null
    • memberCount integer
    • lastMessageAt string (date-time) | null
    • createdBy string | null
    • createdAt string (date-time)
  • nextCursor string | null
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels?limit=50" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
POST /v1/apps/{appId}/channels App server key

Create a channel

For direct kinds the member set is distinct: re-creating with the same members returns the existing channel. For E2EE channels the creating device must then establish the MLS group (claim key packages, post Welcome). Callable with a session token (client) or server key.

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • channelTypeKey string required
  • name string
    Max length 200.
  • memberIds array of string
    Max items 1000.
  • operatorIds array of string
  • metadata object
    • <key> string
  • coverUrl string (uri) | null

Responses

201 Channel (or existing distinct channel — 200). Channel
  • channelId string
  • appId string
  • channelTypeKey string
  • kind string
    One of: direct, group, broadcast.
  • e2ee boolean
  • name string
  • coverUrl string | null
  • metadata object
    • <key> string
  • isFrozen boolean
  • mlsGroupId string | null
  • memberCount integer
  • lastMessageAt string (date-time) | null
  • createdBy string | null
  • createdAt string (date-time)
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channelTypeKey": "direct",
    "memberIds": [
      "user_8m2n1xq4",
      "user_3p9dq5w2"
    ]
  }'
JavaScript (fetch)
const res = await fetch('https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer npk_live_SERVER_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "channelTypeKey": "direct",
    "memberIds": [
      "user_8m2n1xq4",
      "user_3p9dq5w2"
    ]
  }),
});
const data = await res.json();
GET /v1/apps/{appId}/channels/{channelId} App server key

Get a channel

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes

Responses

200 Channel. Channel
  • channelId string
  • appId string
  • channelTypeKey string
  • kind string
    One of: direct, group, broadcast.
  • e2ee boolean
  • name string
  • coverUrl string | null
  • metadata object
    • <key> string
  • isFrozen boolean
  • mlsGroupId string | null
  • memberCount integer
  • lastMessageAt string (date-time) | null
  • createdBy string | null
  • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
PATCH /v1/apps/{appId}/channels/{channelId} App server key

Update channel (name, cover, metadata, freeze)

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes

Request body (optional)

  • name string
  • coverUrl string | null
  • metadata object
    • <key> string
  • isFrozen boolean

Responses

200 Updated channel. Channel
  • channelId string
  • appId string
  • channelTypeKey string
  • kind string
    One of: direct, group, broadcast.
  • e2ee boolean
  • name string
  • coverUrl string | null
  • metadata object
    • <key> string
  • isFrozen boolean
  • mlsGroupId string | null
  • memberCount integer
  • lastMessageAt string (date-time) | null
  • createdBy string | null
  • createdAt string (date-time)
cURL
curl -X PATCH "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Design crew",
    "isFrozen": false
  }'
DELETE /v1/apps/{appId}/channels/{channelId} App server key

Delete a channel

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes

Responses

204 Deleted.
cURL
curl -X DELETE "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"

Members

GET /v1/apps/{appId}/channels/{channelId}/members App server key

List members

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes
limit query integer no Default 50. Min 1. Max 200.
cursor query string no

Responses

200 Members.
  • members array of ChannelMember
    • channelId string
    • userId string
    • role string
      One of: member, operator.
    • mutedUntil string (date-time) | null
    • bannedAt string (date-time) | null
    • lastDeliveredSeq integer
    • lastReadSeq integer
    • unreadCount integer
    • joinedAt string (date-time)
  • nextCursor string | null
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/members?limit=50" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
POST /v1/apps/{appId}/channels/{channelId}/members App server key

Add members

For E2EE channels the caller (an existing member device or operator) must follow up with an MLS Add commit + Welcome; new members cannot decrypt until then.

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes

Request body

  • userIds array of string required
    Max items 100.

Responses

200 Updated member list.
  • members array of ChannelMember
    • channelId string
    • userId string
    • role string
      One of: member, operator.
    • mutedUntil string (date-time) | null
    • bannedAt string (date-time) | null
    • lastDeliveredSeq integer
    • lastReadSeq integer
    • unreadCount integer
    • joinedAt string (date-time)
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/members" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userIds": [
      "user_6w2k9rt8"
    ]
  }'
DELETE /v1/apps/{appId}/channels/{channelId}/members/{userId} App server key

Remove a member (or leave, with session token)

E2EE channels require a subsequent MLS Remove commit from a remaining member; until then the removed device is cryptographically excluded from the NEXT epoch, not past ones.

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes
userId path string yes

Responses

204 Removed.
cURL
curl -X DELETE "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/members/user_8m2n1xq4" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"

Messages

GET /v1/apps/{appId}/channels/{channelId}/messages App server key

List messages (ciphertext envelopes in E2EE channels)

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes
beforeSeq query integer no
afterSeq query integer no
threadParentId query string no
limit query integer no Default 50. Min 1. Max 200.

Responses

200 Messages ordered by seq.
  • messages array of MessageEnvelope
    • messageId string
    • channelId string
    • senderUserId string
    • senderDeviceId string | null
    • seq integer
    • threadParentId string | null
    • mlsEpoch integer | null
    • ciphertext string (base64) | null
    • plaintext PlaintextBody | null
      Opted-out channels only; E2EE channels reject it.
      • type string
        One of: text, file, system.
      • text string
        Max length 20000.
      • attachments array of object
        • url string
        • name string
        • contentType string
        • size integer
      • metadata object
        • <key> string
    • editedAt string (date-time) | null
    • recalledAt string (date-time) | null
    • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/messages?afterSeq=130&limit=50" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
JavaScript (fetch)
const res = await fetch('https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/messages?afterSeq=130&limit=50', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer npk_live_SERVER_KEY',
  },
});
const data = await res.json();
POST /v1/apps/{appId}/channels/{channelId}/messages Session token

Send a message

E2EE channels: ciphertext (MLS application message) required; server assigns seq, stamps time, fans out over WS, dispatches push with an encrypted payload. Opted-out channels: plaintext required. clientMessageId makes the call idempotent per sender. Note: a server key can only send into opted-out channels (it holds no MLS credential) — bots in E2EE channels join as member devices.

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes

Request body

  • clientMessageId string required
    Max length 64.
  • threadParentId string | null
  • mlsEpoch integer | null
  • ciphertext string (base64) | null
  • plaintext PlaintextBody | null
    Opted-out channels only; E2EE channels reject it.
    • type string
      One of: text, file, system.
    • text string
      Max length 20000.
    • attachments array of object
      • url string
      • name string
      • contentType string
      • size integer
    • metadata object
      • <key> string

Responses

201 The authoritative envelope. MessageEnvelope
  • messageId string
  • channelId string
  • senderUserId string
  • senderDeviceId string | null
  • seq integer
  • threadParentId string | null
  • mlsEpoch integer | null
  • ciphertext string (base64) | null
  • plaintext PlaintextBody | null
    Opted-out channels only; E2EE channels reject it.
    • type string
      One of: text, file, system.
    • text string
      Max length 20000.
    • attachments array of object
      • url string
      • name string
      • contentType string
      • size integer
    • metadata object
      • <key> string
  • editedAt string (date-time) | null
  • recalledAt string (date-time) | null
  • createdAt string (date-time)
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/messages" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "clientMessageId": "01J29ZQ8V2-0001",
    "mlsEpoch": 42,
    "ciphertext": "bWxzLWFwcGxpY2F0aW9uLW1lc3NhZ2U="
  }'
JavaScript (fetch)
const res = await fetch('https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/messages', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer nps_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "clientMessageId": "01J29ZQ8V2-0001",
    "mlsEpoch": 42,
    "ciphertext": "bWxzLWFwcGxpY2F0aW9uLW1lc3NhZ2U="
  }),
});
const data = await res.json();
GET /v1/apps/{appId}/channels/{channelId}/messages/{messageId} App server key

Get a message envelope

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes
messageId path string yes

Responses

200 Envelope. MessageEnvelope
  • messageId string
  • channelId string
  • senderUserId string
  • senderDeviceId string | null
  • seq integer
  • threadParentId string | null
  • mlsEpoch integer | null
  • ciphertext string (base64) | null
  • plaintext PlaintextBody | null
    Opted-out channels only; E2EE channels reject it.
    • type string
      One of: text, file, system.
    • text string
      Max length 20000.
    • attachments array of object
      • url string
      • name string
      • contentType string
      • size integer
    • metadata object
      • <key> string
  • editedAt string (date-time) | null
  • recalledAt string (date-time) | null
  • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/messages/msg_9k2p4dr2" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
PATCH /v1/apps/{appId}/channels/{channelId}/messages/{messageId} Session token

Edit a message

Sender-only, within the channel type's editWindowSeconds. E2EE channels: supply new ciphertext (clients also embed an edit op in the E2EE payload so peers verify the edit cryptographically — the envelope swap alone is not trusted). Opted-out: new plaintext.

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes
messageId path string yes

Request body

  • mlsEpoch integer | null
  • ciphertext string (base64) | null
  • plaintext PlaintextBody | null
    Opted-out channels only; E2EE channels reject it.
    • type string
      One of: text, file, system.
    • text string
      Max length 20000.
    • attachments array of object
      • url string
      • name string
      • contentType string
      • size integer
    • metadata object
      • <key> string

Responses

200 Updated envelope. MessageEnvelope
  • messageId string
  • channelId string
  • senderUserId string
  • senderDeviceId string | null
  • seq integer
  • threadParentId string | null
  • mlsEpoch integer | null
  • ciphertext string (base64) | null
  • plaintext PlaintextBody | null
    Opted-out channels only; E2EE channels reject it.
    • type string
      One of: text, file, system.
    • text string
      Max length 20000.
    • attachments array of object
      • url string
      • name string
      • contentType string
      • size integer
    • metadata object
      • <key> string
  • editedAt string (date-time) | null
  • recalledAt string (date-time) | null
  • createdAt string (date-time)
cURL
curl -X PATCH "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/messages/msg_9k2p4dr2" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mlsEpoch": 42,
    "ciphertext": "bmV3LWNpcGhlcnRleHQ="
  }'
DELETE /v1/apps/{appId}/channels/{channelId}/messages/{messageId} App server key

Recall a message (delete for everyone)

Sender within recallWindowSeconds, or an operator/server key any time. Ciphertext is erased server-side; a tombstone (id, seq, recalledAt) remains for sync.

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes
messageId path string yes

Responses

204 Recalled.
cURL
curl -X DELETE "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/messages/msg_9k2p4dr2" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"

Reactions

GET /v1/apps/{appId}/channels/{channelId}/messages/{messageId}/reactions App server key

List reactions (opted-out channels)

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes
messageId path string yes

Responses

200 Reactions grouped by emoji.
  • reactions array of Reaction
    • reactionId string
    • messageId string
    • channelId string
    • userId string
    • emoji string
    • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/messages/msg_9k2p4dr2/reactions" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
POST /v1/apps/{appId}/channels/{channelId}/messages/{messageId}/reactions Session token

Add a reaction (opted-out channels)

In E2EE channels reactions travel INSIDE ciphertext (a reaction payload) and are aggregated client-side; this endpoint returns E2EE_REQUIRED there.

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes
messageId path string yes

Request body

  • emoji string required
    Max length 64.

Responses

201 Reaction. Reaction
  • reactionId string
  • messageId string
  • channelId string
  • userId string
  • emoji string
  • createdAt string (date-time)
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/messages/msg_9k2p4dr2/reactions" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "emoji": "👍"
  }'
DELETE /v1/apps/{appId}/channels/{channelId}/messages/{messageId}/reactions Session token

Remove own reaction (opted-out channels)

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes
messageId path string yes
emoji query string yes

Responses

204 Removed.
cURL
curl -X DELETE "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/messages/msg_9k2p4dr2/reactions?emoji=%F0%9F%91%8D" \
  -H "Authorization: Bearer nps_SESSION_TOKEN"

Receipts

GET /v1/apps/{appId}/channels/{channelId}/receipts App server key

Get per-member receipt high-water marks

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes

Responses

200 Member marks.
  • receipts array of object
    • userId string
    • lastDeliveredSeq integer
    • lastReadSeq integer
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/receipts" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
POST /v1/apps/{appId}/channels/{channelId}/receipts Session token

Mark delivered/read up to a message (client)

High-water mark semantics; also available on the WebSocket (receipt.mark). Receipts are metadata and are visible to the server by design.

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes

Request body

  • kind string required
    One of: delivered, read.
  • messageId string required

Responses

204 Marked and fanned out.
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/receipts" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "read",
    "messageId": "msg_9k2p4dr2"
  }'
JavaScript (fetch)
const res = await fetch('https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/receipts', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer nps_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "kind": "read",
    "messageId": "msg_9k2p4dr2"
  }),
});
if (res.status !== 204) throw new Error(`NoPeek error ${res.status}`);

Moderation

POST /v1/apps/{appId}/channels/{channelId}/moderation/{action} App server key

Ban/mute/freeze operations

Parameters

NameInTypeRequiredNotes
appId path string yes
channelId path string yes
action path string yes One of: ban, unban, mute, unmute, freeze, unfreeze.

Request body (optional)

  • userId string
    Required for ban/unban/mute/unmute.
  • durationSeconds integer | null

Responses

204 Applied.
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/moderation/mute" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "user_3p9dq5w2",
    "durationSeconds": 3600
  }'
JavaScript (fetch)
const res = await fetch('https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/channels/chan_4t9wq1z7/moderation/mute', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer npk_live_SERVER_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "userId": "user_3p9dq5w2",
    "durationSeconds": 3600
  }),
});
if (res.status !== 204) throw new Error(`NoPeek error ${res.status}`);
GET /v1/apps/{appId}/reports App server key

List reports (server key)

Parameters

NameInTypeRequiredNotes
appId path string yes
status query string no One of: open, resolved, dismissed.

Responses

200 Reports.
  • reports array of Report
    • id integer
    • channelId string
    • messageId string | null
    • reporterUserId string
    • reportedUserId string | null
    • category string
    • disclosedContent string | null
    • status string
      One of: open, resolved, dismissed.
    • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/reports?status=open" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
POST /v1/apps/{appId}/reports Session token

Report a message/user (client)

The E2EE moderation path: the REPORTER's device decrypts the offending message locally and voluntarily discloses that plaintext with the report. NoPeek never breaks encryption — disclosure is a member exercising their own right to the content they can already read.

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • channelId string required
  • messageId string | null
  • reportedUserId string | null
  • category string required
    One of: spam, harassment, illegal, self_harm, other.
  • disclosedContent string | null
    Max length 20000.

Responses

201 Report filed; webhook report.created fires.
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/reports" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "channelId": "chan_4t9wq1z7",
    "messageId": "msg_9k2p4dr2",
    "reportedUserId": "user_3p9dq5w2",
    "category": "harassment",
    "disclosedContent": "decrypted text, voluntarily disclosed by the reporter"
  }'

History Backups

Encrypted, client-keyed history archives for new-device sync.

GET /v1/apps/{appId}/users/{userId}/history-backups Session token

List backups (newest first) with download URLs (client)

Parameters

NameInTypeRequiredNotes
appId path string yes
userId path string yes

Responses

200 Backups.
  • backups array of HistoryBackup
    • backupId string
    • userId string
    • deviceId string
    • keyDerivation object
      • scheme string
      • salt string (base64)
      • memoryKib integer
      • iterations integer
    • blobKey string
    • sizeBytes integer
    • manifestHash string
    • downloadUrl string | null
      Pre-signed GET when listed by the owner.
    • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4/history-backups" \
  -H "Authorization: Bearer nps_SESSION_TOKEN"
POST /v1/apps/{appId}/users/{userId}/history-backups Session token

Register an encrypted history backup (client)

Returns a pre-signed PUT URL for the encrypted archive. The backup key is derived on-device from the user's recovery code (argon2id → HKDF); NoPeek stores derivation parameters, never key material.

Parameters

NameInTypeRequiredNotes
appId path string yes
userId path string yes

Request body

  • keyDerivation object required
    • scheme string required
      One of: argon2id-hkdf-v1.
    • salt string (base64) required
    • memoryKib integer required
    • iterations integer required
  • sizeBytes integer required
  • manifestHash string required

Responses

201 Backup slot with upload URL.
  • backup HistoryBackup
    • backupId string
    • userId string
    • deviceId string
    • keyDerivation object
      • scheme string
      • salt string (base64)
      • memoryKib integer
      • iterations integer
    • blobKey string
    • sizeBytes integer
    • manifestHash string
    • downloadUrl string | null
      Pre-signed GET when listed by the owner.
    • createdAt string (date-time)
  • uploadUrl string (uri)
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/users/user_8m2n1xq4/history-backups" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "keyDerivation": {
      "scheme": "argon2id-hkdf-v1",
      "salt": "c2FsdEJ5dGVz",
      "memoryKib": 65536,
      "iterations": 3
    },
    "sizeBytes": 1048576,
    "manifestHash": "sha256:9f2b1c44"
  }'

Uploads

Pre-signed upload slots for client-side-encrypted attachments.

POST /v1/apps/{appId}/uploads Session token

Get a pre-signed slot for an encrypted attachment (client)

Clients encrypt attachments with a fresh AES-256-GCM content key BEFORE upload; the key travels only inside message ciphertext. The blob NoPeek stores is unreadable. Used by all rich content that carries a file: images, video, audio, generic files, and contact/thumbnail images. The SDK exposes this as np.uploadEncrypted(bytes) / channel.sendAttachment(...); structured rich types (poll, contact, calendar_event, location) need no upload — they ride inside the message payload. See the RichMessagePayload schema for the on-the-wire format every SDK agrees on (the server never parses it in E2EE channels).

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • sizeBytes integer required
    Max 104857600.

Responses

201 Slot.
  • blobUrl string
    Stable fetch URL for the encrypted blob.
  • uploadUrl string (uri)
    Pre-signed PUT, expires in 15 min.
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/uploads" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "sizeBytes": 1048576
  }'

Messenger

White-label messenger: turnkey end-user auth (username/password or Cognito), org/referral join codes, and the unified multi-org inbox. No public registration.

POST /v1/apps/{appId}/messenger/login No authentication

Log in with username + password

Turnkey end-user login: the customer needs no backend. Returns a NoPeek session token, the user profile, their workspace memberships, and whether a forced password change / recovery-key save is still pending. Failed attempts are audit-logged.

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • username string required
  • password string required

Responses

200 Session + profile + workspaces. Session
  • sessionToken string
    Short-lived client credential (nps_…). Hand to the SDK; TTL follows the app’s sessionTtlSeconds.
  • expiresAt string (date-time)
  • user MessengerUser
    End-user profile for the white-label messenger. Username is typically the email (admins add users by email); the display handle is separate.
    • userId string
    • username string
    • email string | null
    • nickname string | null
    • avatarUrl string | null
    • statusText string | null
    • mustChangePassword boolean
      True until the user completes their forced first-login password change.
    • hasRecoveryKey boolean
      Whether a recovery-key hint has been stored for this account.
    • lastSeenAt string (date-time) | null
  • workspaces array of Workspace
    • workspaceId string
    • appId string
    • name string
    • slug string | null
    • branding object | null
    • myRole string | null
      Present only when fetched with a session token: the caller’s role. One of: member, admin, owner.
    • createdAt string (date-time)
  • mustChangePassword boolean
  • hasRecoveryKey boolean
401 Incorrect username or password (UNAUTHENTICATED). Error
  • error object
    • code string
    • message string
403 Account deactivated (FORBIDDEN). Error
  • error object
    • code string
    • message string
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/messenger/login" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "string",
    "password": "string"
  }'
POST /v1/apps/{appId}/messenger/cognito-session No authentication

Exchange a Cognito id token for a NoPeek session

The primary login when Cognito is the IdP. The app authenticates the user against Cognito (password/MFA/refresh), then posts the verified idToken here; NoPeek verifies it, provisions/links the user (by cognito_sub, else by email), and mints a session. Requires Cognito to be configured for this deployment.

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • idToken string required
    A verified Cognito ID token (JWT).

Responses

200 Session + profile + workspaces. Session
  • sessionToken string
    Short-lived client credential (nps_…). Hand to the SDK; TTL follows the app’s sessionTtlSeconds.
  • expiresAt string (date-time)
  • user MessengerUser
    End-user profile for the white-label messenger. Username is typically the email (admins add users by email); the display handle is separate.
    • userId string
    • username string
    • email string | null
    • nickname string | null
    • avatarUrl string | null
    • statusText string | null
    • mustChangePassword boolean
      True until the user completes their forced first-login password change.
    • hasRecoveryKey boolean
      Whether a recovery-key hint has been stored for this account.
    • lastSeenAt string (date-time) | null
  • workspaces array of Workspace
    • workspaceId string
    • appId string
    • name string
    • slug string | null
    • branding object | null
    • myRole string | null
      Present only when fetched with a session token: the caller’s role. One of: member, admin, owner.
    • createdAt string (date-time)
  • mustChangePassword boolean
  • hasRecoveryKey boolean
401 Invalid or expired sign-in token (UNAUTHENTICATED). Error
  • error object
    • code string
    • message string
501 Cognito is not configured (NOT_IMPLEMENTED). Error
  • error object
    • code string
    • message string
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/messenger/cognito-session" \
  -H "Content-Type: application/json" \
  -d '{
    "idToken": "string"
  }'
POST /v1/apps/{appId}/messenger/join No authentication

Create an account via an org/referral code

The only self-serve way to get an account — there is no open registration. A valid workspace join or referral code is required (referral codes work only when the workspace allows referral join). Creates the user, adds them to the workspace as a member, and returns a session.

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • code string required
    Workspace join or referral code.
  • username string required
    Max length 64.
  • password string required
  • email string (email) | null
  • displayName string | null
    Display handle; defaults to the username.

Responses

201 Account created; session issued. Session
  • sessionToken string
    Short-lived client credential (nps_…). Hand to the SDK; TTL follows the app’s sessionTtlSeconds.
  • expiresAt string (date-time)
  • user MessengerUser
    End-user profile for the white-label messenger. Username is typically the email (admins add users by email); the display handle is separate.
    • userId string
    • username string
    • email string | null
    • nickname string | null
    • avatarUrl string | null
    • statusText string | null
    • mustChangePassword boolean
      True until the user completes their forced first-login password change.
    • hasRecoveryKey boolean
      Whether a recovery-key hint has been stored for this account.
    • lastSeenAt string (date-time) | null
  • workspaces array of Workspace
    • workspaceId string
    • appId string
    • name string
    • slug string | null
    • branding object | null
    • myRole string | null
      Present only when fetched with a session token: the caller’s role. One of: member, admin, owner.
    • createdAt string (date-time)
  • mustChangePassword boolean
  • hasRecoveryKey boolean
403 Workspace is not accepting referrals (FORBIDDEN). Error
  • error object
    • code string
    • message string
404 Invalid organization code (NOT_FOUND). Error
  • error object
    • code string
    • message string
409 Username taken (ALREADY_EXISTS). Error
  • error object
    • code string
    • message string
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/messenger/join" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "string",
    "username": "string",
    "password": "string"
  }'
POST /v1/apps/{appId}/messenger/join-workspace Session token

Join an additional workspace (client)

For an already-signed-in user: redeem another workspace’s code to become a multi-org member. Its channels then appear in the unified inbox.

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • code string required

Responses

201 Joined; the workspace (with your role). Workspace
  • workspaceId string
  • appId string
  • name string
  • slug string | null
  • branding object | null
  • myRole string | null
    Present only when fetched with a session token: the caller’s role. One of: member, admin, owner.
  • createdAt string (date-time)
404 Invalid organization code (NOT_FOUND). Error
  • error object
    • code string
    • message string
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/messenger/join-workspace" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "string"
  }'
GET /v1/apps/{appId}/messenger/inbox Session token

Unified multi-org inbox (client)

Every channel the caller is a member of across all their workspaces, newest-activity first, each tagged with its workspace. Includes the caller’s unread count and role per channel.

Parameters

NameInTypeRequiredNotes
appId path string yes

Responses

200 Inbox + the workspaces it spans.
  • inbox array of InboxItem
    • channelId string
    • appId string
    • channelTypeKey string
    • kind string
      One of: direct, group, broadcast.
    • e2ee boolean
    • name string
    • coverUrl string | null
    • metadata object
      • <key> string
    • isFrozen boolean
    • mlsGroupId string | null
    • memberCount integer
    • lastMessageAt string (date-time) | null
    • createdBy string | null
    • createdAt string (date-time)
    • workspaceId string | null
    • workspaceName string | null
    • communityId string | null
    • unreadCount integer
    • myRole string
      One of: member, operator.
  • workspaces array of object
    • workspaceId string
    • name string
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/messenger/inbox" \
  -H "Authorization: Bearer nps_SESSION_TOKEN"
GET /v1/apps/{appId}/messenger/me Session token

Get my profile (client)

Parameters

NameInTypeRequiredNotes
appId path string yes

Responses

200 Profile. MessengerUser
  • userId string
  • username string
  • email string | null
  • nickname string | null
  • avatarUrl string | null
  • statusText string | null
  • mustChangePassword boolean
    True until the user completes their forced first-login password change.
  • hasRecoveryKey boolean
    Whether a recovery-key hint has been stored for this account.
  • lastSeenAt string (date-time) | null
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/messenger/me" \
  -H "Authorization: Bearer nps_SESSION_TOKEN"
PATCH /v1/apps/{appId}/messenger/me Session token

Update my profile (client)

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body (optional)

  • nickname string
  • avatarUrl string | null
  • statusText string | null

Responses

200 Updated profile. MessengerUser
  • userId string
  • username string
  • email string | null
  • nickname string | null
  • avatarUrl string | null
  • statusText string | null
  • mustChangePassword boolean
    True until the user completes their forced first-login password change.
  • hasRecoveryKey boolean
    Whether a recovery-key hint has been stored for this account.
  • lastSeenAt string (date-time) | null
cURL
curl -X PATCH "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/messenger/me" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "nickname": "string"
  }'
POST /v1/apps/{appId}/messenger/change-password Session token

Change my password (client)

Lossless: because the user proves the current password, the client can re-wrap the E2EE backup data-key under the new password (it re-runs backup afterwards). Clears the mustChangePassword flag.

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • currentPassword string required
  • newPassword string required

Responses

200 Changed.
  • ok boolean
401 Current password incorrect (UNAUTHENTICATED). Error
  • error object
    • code string
    • message string
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/messenger/change-password" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "currentPassword": "string",
    "newPassword": "string"
  }'
POST /v1/apps/{appId}/messenger/email-recovery-key Session token

Save a recovery-key hint (+ optionally email the key) (client)

The recovery code is generated on-device (it wraps the E2EE data key); this stores a last-4 hint and, if the workspace opted in (email_recovery_key) and the account has an email, emails the full code. Emailing a key that can open backups is a deliberate escrow trade-off — see the Backup & recovery guide.

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • recoveryCode string required

Responses

200 Hint stored.
  • ok boolean
  • emailed boolean
  • hint string
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/messenger/email-recovery-key" \
  -H "Authorization: Bearer nps_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "recoveryCode": "string"
  }'
POST /v1/apps/{appId}/messenger/forgot-password No authentication

Request a password-reset code

Emails a 6-char, 30-minute reset code to the account (matched by username or email). Always returns ok — it never reveals whether an account exists.

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • username string required
    Username or email.

Responses

200 Accepted (email sent if the account exists).
  • ok boolean
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/messenger/forgot-password" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "string"
  }'
POST /v1/apps/{appId}/messenger/reset-password No authentication

Reset password with a code

Submits the emailed code + a new password. A forgotten password cannot re-wrap the old E2EE data-key, so if recoveryRequired is true the client must supply the saved recovery key (or rely on org-escrow) to keep old messages — otherwise history starts fresh.

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • username string required
    Username or email.
  • code string required
  • newPassword string required

Responses

200 Password reset.
  • ok boolean
  • userId string
  • recoveryRequired boolean
    Prompt for the recovery key on this device to restore history.
  • recoveryKeyHint string | null
401 Invalid or expired reset code (UNAUTHENTICATED). Error
  • error object
    • code string
    • message string
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/messenger/reset-password" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "string",
    "code": "string",
    "newPassword": "string"
  }'
POST /v1/apps/{appId}/messenger/users App server key

Admin-create a messenger user

Server-key only (no public registration). Username defaults to the email. If no password is given a temporary one is generated and returned once; the user is flagged mustChangePassword. Optionally adds the user to a workspace and mirrors the account into Cognito when configured.

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • username string required
    Usually the email. Max length 64.
  • password string | null
    Omit to auto-generate a temporary password.
  • email string (email) | null
  • displayName string | null
  • workspaceId string | null
    Add the new user to this workspace.
  • role string
    One of: member, admin, owner. Default "member".

Responses

201 User created; initial password shown once.
  • user MessengerUser
    End-user profile for the white-label messenger. Username is typically the email (admins add users by email); the display handle is separate.
    • userId string
    • username string
    • email string | null
    • nickname string | null
    • avatarUrl string | null
    • statusText string | null
    • mustChangePassword boolean
      True until the user completes their forced first-login password change.
    • hasRecoveryKey boolean
      Whether a recovery-key hint has been stored for this account.
    • lastSeenAt string (date-time) | null
  • initialPassword string
    Temporary or supplied password — shown once.
  • mustChangePassword boolean
409 Username taken (ALREADY_EXISTS). Error
  • error object
    • code string
    • message string
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/messenger/users" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "string",
    "role": "member"
  }'
POST /v1/apps/{appId}/messenger/users/{userId}/reset-password App server key

Admin-reset a user’s password

Server-key only. Generates a new temporary password (returned once) and re-flags mustChangePassword. Mirrors to Cognito when configured. The user needs their saved recovery key (or org-escrow) to keep old messages afterwards.

Parameters

NameInTypeRequiredNotes
appId path string yes
userId path string yes

Responses

200 Reset; temporary password shown once.
  • userId string
  • temporaryPassword string
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/messenger/users/user_8m2n1xq4/reset-password" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"

Workspaces

Organizations end users join, their communities, membership and roles. Join & referral codes gate access.

GET /v1/apps/{appId}/workspaces App server key

List workspaces (mine, or all with a server key)

With a session token: the workspaces the caller belongs to (each with myRole). With a server/org-admin key: every workspace in the app, including codes.

Parameters

NameInTypeRequiredNotes
appId path string yes

Responses

200 Workspaces.
  • workspaces array of Workspace
    • workspaceId string
    • appId string
    • name string
    • slug string | null
    • branding object | null
    • myRole string | null
      Present only when fetched with a session token: the caller’s role. One of: member, admin, owner.
    • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/workspaces" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
POST /v1/apps/{appId}/workspaces App server key

Create a workspace

Server/org-admin key. Auto-generates a join code and a referral code (returned in the admin view).

Parameters

NameInTypeRequiredNotes
appId path string yes

Request body

  • name string required
    Max length 200.
  • slug string | null
  • branding object | null
  • allowReferralJoin boolean
    Default true.

Responses

201 Workspace (with codes). WorkspaceAdmin
  • workspaceId string
  • appId string
  • name string
  • slug string | null
  • branding object | null
  • myRole string | null
    Present only when fetched with a session token: the caller’s role. One of: member, admin, owner.
  • createdAt string (date-time)
  • joinCode string
    Short code that admits new users as workspace members.
  • referralCode string
    Member-shareable code; honored only when allowReferralJoin is true.
  • allowReferralJoin boolean
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/workspaces" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "string",
    "allowReferralJoin": true
  }'
GET /v1/apps/{appId}/workspaces/{workspaceId} App server key

Get a workspace

Members see the basic view (with myRole); server/org-admin keys see the admin view with codes.

Parameters

NameInTypeRequiredNotes
appId path string yes
workspaceId path string yes

Responses

200 Workspace. Workspace
  • workspaceId string
  • appId string
  • name string
  • slug string | null
  • branding object | null
  • myRole string | null
    Present only when fetched with a session token: the caller’s role. One of: member, admin, owner.
  • createdAt string (date-time)
403 Not a member (FORBIDDEN). Error
  • error object
    • code string
    • message string
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/workspaces/ws_6b3n8kq2" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
POST /v1/apps/{appId}/workspaces/{workspaceId}/rotate-codes App server key

Rotate join & referral codes

Workspace admin/owner (or server key). Invalidates the old codes and returns fresh ones.

Parameters

NameInTypeRequiredNotes
appId path string yes
workspaceId path string yes

Responses

200 Workspace with new codes. WorkspaceAdmin
  • workspaceId string
  • appId string
  • name string
  • slug string | null
  • branding object | null
  • myRole string | null
    Present only when fetched with a session token: the caller’s role. One of: member, admin, owner.
  • createdAt string (date-time)
  • joinCode string
    Short code that admits new users as workspace members.
  • referralCode string
    Member-shareable code; honored only when allowReferralJoin is true.
  • allowReferralJoin boolean
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/workspaces/ws_6b3n8kq2/rotate-codes" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
GET /v1/apps/{appId}/workspaces/{workspaceId}/members App server key

List workspace members

Parameters

NameInTypeRequiredNotes
appId path string yes
workspaceId path string yes

Responses

200 Members with their workspace role.
  • members array of object
    • userId string
    • username string
    • email string | null
    • nickname string | null
    • avatarUrl string | null
    • statusText string | null
    • mustChangePassword boolean
      True until the user completes their forced first-login password change.
    • hasRecoveryKey boolean
      Whether a recovery-key hint has been stored for this account.
    • lastSeenAt string (date-time) | null
    • role string
      One of: member, admin, owner.
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/workspaces/ws_6b3n8kq2/members" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
POST /v1/apps/{appId}/workspaces/{workspaceId}/members App server key

Add a member

Workspace admin/owner (or server key). The user must already exist in the app.

Parameters

NameInTypeRequiredNotes
appId path string yes
workspaceId path string yes

Request body

  • userId string required
  • role string
    One of: member, admin, owner. Default "member".

Responses

201 Added.
  • ok boolean
404 User not found in this app (NOT_FOUND). Error
  • error object
    • code string
    • message string
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/workspaces/ws_6b3n8kq2/members" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "user_8m2n1xq4",
    "role": "member"
  }'
PATCH /v1/apps/{appId}/workspaces/{workspaceId}/members/{userId} App server key

Set a member’s role

Workspace admin/owner (or server key).

Parameters

NameInTypeRequiredNotes
appId path string yes
workspaceId path string yes
userId path string yes

Request body

  • role string required
    One of: member, admin, owner.

Responses

204 Updated.
cURL
curl -X PATCH "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/workspaces/ws_6b3n8kq2/members/user_8m2n1xq4" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "member"
  }'
DELETE /v1/apps/{appId}/workspaces/{workspaceId}/members/{userId} App server key

Remove a member

Workspace admin/owner (or server key).

Parameters

NameInTypeRequiredNotes
appId path string yes
workspaceId path string yes
userId path string yes

Responses

204 Removed.
cURL
curl -X DELETE "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/workspaces/ws_6b3n8kq2/members/user_8m2n1xq4" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
GET /v1/apps/{appId}/workspaces/{workspaceId}/communities App server key

List communities

Parameters

NameInTypeRequiredNotes
appId path string yes
workspaceId path string yes

Responses

200 Communities.
  • communities array of Community
    • communityId string
    • workspaceId string
    • name string
    • description string | null
    • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/workspaces/ws_6b3n8kq2/communities" \
  -H "Authorization: Bearer npk_live_SERVER_KEY"
POST /v1/apps/{appId}/workspaces/{workspaceId}/communities App server key

Create a community

Workspace admin/owner (or server key).

Parameters

NameInTypeRequiredNotes
appId path string yes
workspaceId path string yes

Request body

  • name string required
    Max length 200.
  • description string | null

Responses

201 Community. Community
  • communityId string
  • workspaceId string
  • name string
  • description string | null
  • createdAt string (date-time)
cURL
curl -X POST "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/workspaces/ws_6b3n8kq2/communities" \
  -H "Authorization: Bearer npk_live_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "string"
  }'

App configuration

Public force-update policy, session auto-logoff TTL, and the superadmin global policy.

GET /v1/app-config No authentication

Get force-update policy + session settings

Public. Safe to poll every ~30s. With ?appId= the per-app policy overlay is merged over the global policy and the app’s session TTL is included. serverTime lets clients detect drift for session expiry.

Parameters

NameInTypeRequiredNotes
appId query string no

Responses

200 Effective policy, session settings, and server time.
  • policy AppPolicy
    Capacitor remote-load force-update policy. Clients poll GET /v1/app-config every ~30s; a change in refreshToken (or a min-version gate the running build fails) triggers the update prompt.
    • forceRefreshEnabled boolean
    • refreshToken string
      Opaque token; when it changes, running clients reload.
    • minWebBuild string | null
    • minIosVersion string | null
    • minAndroidVersion string | null
    • title string
    • message string
    • iosUpdateUrl string | null
    • androidUpdateUrl string | null
  • session object
    • sessionTtlSeconds integer
      Present only when ?appId= is supplied.
  • serverTime string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/app-config"
PATCH /v1/admin/app-config Org admin key

Set the global force-update policy

Superadmin. Merges the given fields into the NoPeek-wide policy used by marketing/admin sites and as the base for per-app overlays.

Request body (optional) AppPolicy

  • forceRefreshEnabled boolean
  • refreshToken string
    Opaque token; when it changes, running clients reload.
  • minWebBuild string | null
  • minIosVersion string | null
  • minAndroidVersion string | null
  • title string
  • message string
  • iosUpdateUrl string | null
  • androidUpdateUrl string | null

Responses

200 Updated policy.
  • policy AppPolicy
    Capacitor remote-load force-update policy. Clients poll GET /v1/app-config every ~30s; a change in refreshToken (or a min-version gate the running build fails) triggers the update prompt.
    • forceRefreshEnabled boolean
    • refreshToken string
      Opaque token; when it changes, running clients reload.
    • minWebBuild string | null
    • minIosVersion string | null
    • minAndroidVersion string | null
    • title string
    • message string
    • iosUpdateUrl string | null
    • androidUpdateUrl string | null
cURL
curl -X PATCH "https://api.nopeekapi.com/v1/admin/app-config" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "forceRefreshEnabled": true,
    "refreshToken": "string",
    "title": "string",
    "message": "string"
  }'
POST /v1/admin/app-config/force-refresh Org admin key

Fire a global force-refresh

Superadmin. Bumps refreshToken so every running client reloads to the latest build. Optional title/message customize the prompt.

Request body (optional)

  • title string
  • message string

Responses

200 Updated policy.
  • policy AppPolicy
    Capacitor remote-load force-update policy. Clients poll GET /v1/app-config every ~30s; a change in refreshToken (or a min-version gate the running build fails) triggers the update prompt.
    • forceRefreshEnabled boolean
    • refreshToken string
      Opaque token; when it changes, running clients reload.
    • minWebBuild string | null
    • minIosVersion string | null
    • minAndroidVersion string | null
    • title string
    • message string
    • iosUpdateUrl string | null
    • androidUpdateUrl string | null
cURL
curl -X POST "https://api.nopeekapi.com/v1/admin/app-config/force-refresh" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "string",
    "message": "string"
  }'

Admin

Org-scoped and superadmin operations: tamper-evident audit trails, chain verification, usage reports and platform metrics.

GET /v1/apps/{appId}/audit-logs Org admin key

Org-scoped audit trail

The tamper-evident audit trail for one app — an org admin (or superadmin) sees only their own app’s events. Newest first. Metadata only; message bodies are E2EE and never logged.

Parameters

NameInTypeRequiredNotes
appId path string yes
limit query integer no Default 200. Min 1. Max 1000.
action query string no
actorId query string no
before query integer no Return entries with seq < before (pagination).

Responses

200 Audit entries.
  • entries array of AuditEntry
    • auditId string
    • seq integer
      Monotonic sequence used for ordering and the before= cursor.
    • orgId string | null
    • appId string | null
    • workspaceId string | null
    • actorType string
      e.g. user, app_server, org_admin, system.
    • actorId string | null
    • action string
      e.g. auth.login.success, admin.user.create, auth.password.reset_failed.
    • targetType string | null
    • targetId string | null
    • outcome string
      One of: success, failure, denied.
    • ip string | null
    • userAgent string | null
    • metadata object
    • hash string
      SHA-256 hex of this row’s link in the chain.
    • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/apps/app_7f3kq2c9/audit-logs" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY"
GET /v1/admin/audit Org admin key

Platform-wide audit trail (superadmin)

Every org’s audit events, filterable. Superadmin only.

Parameters

NameInTypeRequiredNotes
limit query integer no Default 200. Min 1. Max 1000.
appId query string no
orgId query string no
actorId query string no
action query string no
before query integer no

Responses

200 Audit entries.
  • entries array of AuditEntry
    • auditId string
    • seq integer
      Monotonic sequence used for ordering and the before= cursor.
    • orgId string | null
    • appId string | null
    • workspaceId string | null
    • actorType string
      e.g. user, app_server, org_admin, system.
    • actorId string | null
    • action string
      e.g. auth.login.success, admin.user.create, auth.password.reset_failed.
    • targetType string | null
    • targetId string | null
    • outcome string
      One of: success, failure, denied.
    • ip string | null
    • userAgent string | null
    • metadata object
    • hash string
      SHA-256 hex of this row’s link in the chain.
    • createdAt string (date-time)
cURL
curl -X GET "https://api.nopeekapi.com/v1/admin/audit" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY"
GET /v1/admin/audit/verify Org admin key

Verify the audit hash chain (superadmin)

Recomputes the hash chain (optionally for one app) and reports whether it is intact. If broken, returns the audit id of the first bad link.

Parameters

NameInTypeRequiredNotes
appId query string no Verify a single app’s chain instead of the whole log.

Responses

200 Verification result.
  • intact boolean
  • verifiedEntries integer
    Present when intact.
  • brokenAt string
    Audit id of the first broken link (when not intact).
cURL
curl -X GET "https://api.nopeekapi.com/v1/admin/audit/verify" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY"
GET /v1/admin/metrics Org admin key

Platform metrics (superadmin)

MAU/DAU, message volume, live concurrency, error/health counters, and plan mix.

Responses

200 Metrics. PlatformMetrics
  • totals object
    • orgs integer
    • apps integer
    • users integer
    • channels integer
    • messages integer
  • activity object
    • dau integer
    • mau integer
    • messagesToday integer
    • messagesThisMonth integer
  • live object
    • concurrentConnections integer
    • clusterNodes integer
  • health object
    • authFailures24h integer
    • webhookBacklog integer
    • webhookFailing integer
  • plans object
    Count of orgs per plan.
    • <key> integer
cURL
curl -X GET "https://api.nopeekapi.com/v1/admin/metrics" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY"
GET /v1/orgs/usage Org admin key

My org’s usage vs plan limits

Org-admin key. Current apps/users/MAU/messages/workspaces against plan ceilings, with proximity and warnings.

Responses

200 Usage report. UsageReport
  • plan string
    One of: free, starter, pro, enterprise.
  • subscriptionStatus string | null
  • usage object
    • apps integer
    • users integer
    • mau integer
    • messagesThisMonth integer
    • workspaces integer
  • limits object
    Plan ceilings. Enterprise is effectively unlimited.
    • apps integer
    • users integer
    • mau integer
    • messagesPerMonth integer
    • workspaces integer
  • proximity object
    Per-metric detail keyed by usage metric.
    • <key> object
  • warnings array of object
    • metric string
    • status string
      One of: warning, over.
    • used integer
    • limit integer
cURL
curl -X GET "https://api.nopeekapi.com/v1/orgs/usage" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY"
GET /v1/admin/orgs/{orgId}/usage Org admin key

Any org’s usage (superadmin)

Parameters

NameInTypeRequiredNotes
orgId path string yes

Responses

200 Usage report. UsageReport
  • plan string
    One of: free, starter, pro, enterprise.
  • subscriptionStatus string | null
  • usage object
    • apps integer
    • users integer
    • mau integer
    • messagesThisMonth integer
    • workspaces integer
  • limits object
    Plan ceilings. Enterprise is effectively unlimited.
    • apps integer
    • users integer
    • mau integer
    • messagesPerMonth integer
    • workspaces integer
  • proximity object
    Per-metric detail keyed by usage metric.
    • <key> object
  • warnings array of object
    • metric string
    • status string
      One of: warning, over.
    • used integer
    • limit integer
cURL
curl -X GET "https://api.nopeekapi.com/v1/admin/orgs/org_2p7m4xd8/usage" \
  -H "Authorization: Bearer npk_live_ORG_ADMIN_KEY"