Passkey-X
Developers

Passkey-X API reference

Three REST APIs, one zero-knowledge boundary. Build on the Customer API for signed-in users, connect HR, ITSM, SIEM and GRC tools with the Organization API, and give scripts and CI pipelines secrets with the Agent API. Every endpoint has cURL, JavaScript and Python samples and a live Try-it console.

Format
REST · JSON over HTTPS
Current version
2026-10-01 · Org API 1.7
Customer API
https://passkey-x.com/api
Organization API
https://passkey-x.com/api/org
Endpoints
93 documented · OpenAPI 3.1

Overview

Pick the API that matches who is calling. Every API returns JSON, uses the same error format and carries an x-request-id header you can quote to support.

Quickstart

  1. Check the API is reachable. No token needed.
    Request
    curl -s https://passkey-x.com/api/v1/health
    
    # → {"status":"ok"}
  2. Get credentials. For your own data, create a personal API key in Passkey-X → Developers → API keys: pick its scopes and expiry, and limit it to your IP addresses. Then check it:
    Request
    export PASSKEY_X_PERSONAL_KEY='pxu_…'
    
    curl -s https://passkey-x.com/api/v1/me -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"
    
    # → { "credential": "personal_api_key", "your_ip": "203.0.113.24", "key": { "scopes": ["vault:read", "sync:read"], … } }
    For your organization, create a scoped key in Admin console → Integrations → API keys (step-by-step).
  3. Make your first call. Check the key and its scopes, then pull the newest audit events:
    Request
    export PASSKEY_X_API_KEY='pxk_…'
    
    curl -s 'https://passkey-x.com/api/org/v1/me' -H "Authorization: Bearer $PASSKEY_X_API_KEY"
    
    curl -s 'https://passkey-x.com/api/org/v1/audit-events?after=0&limit=100' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
    
    # → { "data": [ … ], "next_after": 18342, "has_more": true }

Try it live

Open any endpoint below and choose Try it to send a real request from this page, or Show example response to see what comes back without a key. Requests go straight to the Passkey-X API on this site (/api, /api/org, /api/agent). Requests that change data ask you to confirm first.

Signed in to Passkey-X? The console in Developers uses your session automatically, keeps a list of your recent requests and makes one-hour test keys in one click.

Test credentials

Kept only in this tab’s memory and sent only to the Passkey-X API on this site. Use a short-lived, read-only key for testing (Developers → API keys → Make a test key); reloading the page forgets everything.

Postman and OpenAPI

The Postman collection has every endpoint below, grouped by API, with example bodies, saved example responses and tests that check the status code, the x-request-id header and the error shape. Folder-level Bearer auth reads {{userToken}}, {{orgApiKey}} and {{agentToken}}.

  1. Download the collection and the environment, then in Postman choose Import and drop both files.
  2. Select the Passkey-X (production) environment and paste your key into orgApiKey (it is marked secret).
  3. Send Describe this key first, then run a folder with the Collection Runner to test a whole API.
Run the collection in CI with Newman
npx newman run https://passkey-x.com/api-docs/postman-collection.json \
  --env-var "orgApiKey=$PASSKEY_X_API_KEY" \
  --folder "Key and audit"

Prefer code generation? The OpenAPI 3.1 file works with openapi-generator, Insomnia, Bruno and Stoplight.

Authentication

APISendWhere it comes from
Customer APIAuthorization: Bearer pxu_…Personal API key, made in Passkey-X → Developers → API keys. Choose its scopes (vault:read, vault:write, workspaces:read, sync:read, access:read, access:write), when it expires (1–365 days) and, ideally, the IP addresses it may be used from. Shown once; Passkey-X keeps only a hash. Calls run as you under the same access rules as your session. One-click test keys are read-only and expire after one hour.
Customer API (in the app)Authorization: Bearer <USER_ACCESS_TOKEN>The short-lived access token of a Passkey-X session, used by the apps and by the console in Developers. If the account uses two-step verification, the session must have completed it, or you get 403 mfa_required. Prefer a personal API key for scripts.
Organization APIAuthorization: Bearer pxk_…Owners and admins create scoped keys in Admin console → Integrations → API keys. Shown once, expire after 1–365 days, revocable any time, optionally limited to IP addresses, and one-hour read-only test keys for consoles and Postman. Every call is attributed to the key in the organization’s Logs.
Agent APIAuthorization: Bearer pxa1.<agent id>.<secret>The one-time agent token from the admin console. Its private key part never leaves the machine; only the agent ID and secret are sent.

Never put Supabase secret or service-role keys, Paddle API keys or Sent keys in browser or integration client code. Store API keys in your tool’s secret store.

Zero-knowledge boundary

Encrypt vault content in the trusted client before sending it. Never submit plaintext passwords, recovery keys, private keys, provider tokens, or raw page/form content. Requests that contain fields such as password or private_key are rejected with 422 plaintext_rejected. The Organization API never returns vault content, names or keys: onboarding, handover, timelines and external-share endpoints describe things by metadata only.

Errors

Every error has the same shape. Use code in your logic, show message to people, and quote request_id (also sent as the x-request-id header) when you contact support. Validation errors add field.

Error response
{ "error": { "code": "validation_failed", "message": "nonce must be …", "request_id": "6f1c…", "field": "nonce" } }
StatusCodesWhat to do
400invalid_jsoninvalid_parameterinvalid_bodyThe body isn’t valid JSON, or a parameter is out of range. Fix the request.
401unauthorizedThe token or key is missing, expired or revoked. Refresh the session once, or use a new key.
403forbiddeninsufficient_scopeip_not_allowedsession_requiredplan_requiredaddon_requiredseat_requiredsignature_requiredmfa_requiredidentity_inactiveNot allowed. forbidden (Organization API) or insufficient_scope (Customer API, see WWW-Authenticate): the key needs another scope. ip_not_allowed: the key has an IP allowlist without this address. session_required: only a signed-in session can do this (for example create keys). plan_required: the endpoint needs the Business plan. addon_required: the organization needs the add-on (Remote). seat_required: the key's owner needs a Remote seat. signature_required: an administrator must sign this Controller action in the admin console. mfa_required: use a session that completed two-step sign-in.
404not_foundThe resource doesn’t exist or isn’t visible to you.
405method_not_allowedThe path exists but not for that method. See the Allow header.
409already_existsconflictIt already exists or was already decided. A repeated create with the same id is safe to treat as done.
410goneA removed route (/v1/connectors, /v1/saas).
412revision_conflictThe item changed since you read it. Fetch it, merge, re-encrypt and retry with the new ETag.
413payload_too_largeThe body is over 256 KB.
415unsupported_media_typeSend Content-Type: application/json.
422validation_failedplaintext_rejectedidempotency_key_reusedA field is invalid (see field), the body looks like plaintext secrets, or an Idempotency-Key was reused for a different request.
429rate_limitedSlow down and wait Retry-After seconds, with jitter.
500 / 503internal_errorservice_unavailableunavailableSomething went wrong on our side, or the service is briefly unavailable. Retry safe requests with backoff.

Rate limits

APILimitHeaders
Customer API120 requests per minute per personal API key, counted centrally. With a session token about 120 per minute per account (kept per server instance, so treat it as a guide).X-RateLimit-Limit, X-RateLimit-Remaining on authenticated responses, Retry-After on 429
Organization API300 requests per minute per keyX-RateLimit-Limit, X-RateLimit-Remaining on every response, Retry-After (seconds) on 429
Agent APIOne request per second per agentRetry-After on 429

On 429, wait Retry-After seconds and back off with jitter. Never retry unsafe requests blindly after a timeout.

Pagination and sync

GET /v1/vault-items returns { "items": [...], "next_cursor": "…", "has_more": true }. While has_more is true, call again with ?cursor=<next_cursor>. The cursor is opaque: don’t build or change it.

GET /v1/sync/changes returns a string cursor and has_more; store the cursor and send it back on the next call.

Every Organization API list (1.5) answers { "data": [...], "has_more": true, "next_cursor": "…" }: send ?cursor=<next_cursor> back while has_more is true (offset still works). /v1/logs pages newest first and filters by type, from/to, actor, level, status and q; short lists (alerts, access requests, external shares, handovers, weekly reports) also take since, until and q. /v1/audit-events keeps next_after.

Updating safely with ETag and If-Match

Reading or writing an item returns an ETag header such as "3": the item’s current revision. Send it back as If-Match on PATCH and DELETE. If someone changed the item in the meantime you get 412: fetch the latest revision, merge locally, re-encrypt and try again.

Retries and Idempotency-Key. Organization API writes (POST, PUT, PATCH, DELETE) honour an Idempotency-Key header (8–128 characters): the first answer is kept for 24 hours and a repeat returns it again with Idempotent-Replayed: true, so a retried device code isn’t issued twice. On the Customer API the header is reserved: creates are still safe to retry because you choose the item id (a repeat returns 409 already_exists), and updates are protected by If-Match. Organization API writes are safe to repeat: inviting the same email again, approving a decided request or extending a finished onboarding returns the current state or 409 conflict.

Versioning and headers

The path version is /v1. Customer API responses carry API-Version: 2026-10-01; additive changes keep the same version, and breaking changes get a new one with notice. Every response carries x-request-id. Customer API responses also carry Cache-Control: no-store and X-Content-Type-Options: nosniff. Never log request bodies, tokens or ciphertext: log the request ID instead.

The Organization and Agent APIs are now also served from this site at https://passkey-x.com/api/org and https://passkey-x.com/api/agent. The original URLs, such as https://rqblosdixajthfdzqotj.supabase.co/functions/v1/org-api/v1, keep working.

All endpoints at a glance

Every endpoint of the three APIs in one table. Filter by task or scope, then open an endpoint for its parameters, samples and the Try-it console.

93 of 93
MethodPathWhat it doesAPIScope or credentialSince
GET/v1/healthCheck the API is upCustomerNone—
GET/v1/meWho am ICustomerAny key1.7
GET/v1/api-keysList your personal API keysCustomerAny key1.7
POST/v1/api-keysCreate a personal API keyCustomerSession only1.7
PATCH/v1/api-keys/{key_id}Change a key's IP allowlistCustomerSession only1.7
DELETE/v1/api-keys/{key_id}Revoke a personal API keyCustomerAny key1.7
GET/v1/api-keys/{key_id}/activityA key's recent calls and addressesCustomerAny key1.7
GET/v1/item-typesList item typesCustomerAny key—
GET/v1/workspacesList your workspacesCustomerworkspaces:read—
GET/v1/workspaces/{workspace_id}/membersList workspace membersCustomerworkspaces:read—
GET/v1/vault-itemsList vault itemsCustomervault:read—
GET/v1/vault-items/{item_id}Get one itemCustomervault:read—
POST/v1/vault-itemsCreate an encrypted itemCustomervault:write—
PATCH/v1/vault-items/{item_id}Add a new revisionCustomervault:write—
DELETE/v1/vault-items/{item_id}Delete an itemCustomervault:write—
GET/v1/sync/changesRead the change feedCustomersync:read—
GET/v1/missionsList missionsCustomeraccess:read—
GET/v1/access-requestsList access requestsCustomeraccess:read—
POST/v1/access-requestsRequest accessCustomeraccess:write—
POST/v1/access-requests/{request_id}/decisionApprove or deny a requestCustomeraccess:write—
GET/v1/access-grantsList access grantsCustomeraccess:read—
GET/v1/meDescribe this keyOrganization——
GET/v1/logsRead logsOrganizationlogs:read1.5
GET/v1/audit-eventsRead audit eventsOrganizationaudit:read—
GET/v1/items/{item_id}/timelineWho used a passwordOrganizationaudit:read1.2
GET/v1/alertsList security alertsOrganizationalerts:read—
PATCH/v1/alerts/{alert_id}Update an alertOrganizationalerts:write—
GET/v1/security/summarySecurity summaryOrganizationreports:read—
GET/v1/reports/weeklyWeekly reportsOrganizationreports:read—
GET/v1/policiesList security policiesOrganizationpolicies:read1.2
GET/v1/storageStorage reportOrganizationstorage:read1.3
GET/v1/insightsInsights and Trust IndexOrganizationinsights:read1.3
GET/v1/documentsDocument registerOrganizationdocuments:read1.3
GET/v1/documents/{document_id}One documentOrganizationdocuments:read1.3
POST/v1/documents/verifyVerify a documentOrganizationdocuments:read1.3
GET/v1/company-group/reportCompany group reportOrganizationreports:read1.3
GET/v1/securitySecurity summaryOrganizationsecurity:read1.4
GET/v1/incidentsIncidentsOrganizationsecurity:read1.4
GET/v1/device-trustDevice trustOrganizationsecurity:read1.4
GET/v1/companyCompany profileOrganizationcompany:read1.5
GET/v1/company/devicesCompany devices and codesOrganizationcompany:read1.5
POST/v1/company/device-codesIssue a device codeOrganizationdevices:write1.5
DELETE/v1/company/devices/{device_id}Remove a company deviceOrganizationdevices:write1.5
DELETE/v1/company/device-codes/{code_id}Cancel a device codeOrganizationdevices:write1.5
PUT/v1/policies/{policy_type}Set and enforce a policyOrganizationpolicies:write1.5
DELETE/v1/policies/{policy_type}Stop enforcing a policyOrganizationpolicies:write1.5
POST/v1/members/{identity_id}/blockBlock a memberOrganizationmembers:write1.5
POST/v1/members/{identity_id}/unblockUnblock a memberOrganizationmembers:write1.5
GET/v1/membersList membersOrganizationmembers:read—
POST/v1/membersInvite a memberOrganizationmembers:write—
POST/v1/members/{identity_id}/suspendSuspend a memberOrganizationmembers:write—
POST/v1/members/{identity_id}/reactivateReactivate a memberOrganizationmembers:write—
DELETE/v1/members/{identity_id}Offboard a memberOrganizationmembers:write—
GET/v1/invitationsList open invitationsOrganizationmembers:read—
DELETE/v1/invitations/{invitation_id}Cancel an invitationOrganizationmembers:write—
GET/v1/onboardingOnboarding progressOrganizationonboarding:read1.2
POST/v1/onboarding/{plan_id}/remindSend a reminderOrganizationonboarding:write1.2
POST/v1/onboarding/{plan_id}/extendExtend the deadlineOrganizationonboarding:write1.2
POST/v1/onboarding/{plan_id}/resumeResume paused onboardingOrganizationonboarding:write1.2
POST/v1/onboarding/{plan_id}/cancelCancel onboardingOrganizationonboarding:write1.2
GET/v1/member-securityMember security for auditsOrganizationreports:read1.2
GET/v1/handoversList handoversOrganizationhandover:read1.2
GET/v1/handovers/previewPreview a handoverOrganizationhandover:read1.2
POST/v1/handoversHand over accessOrganizationhandover:write1.2
GET/v1/workspacesList shared vaultsOrganizationworkspaces:read—
GET/v1/groupsList directory groupsOrganizationgroups:read—
GET/v1/access-requestsList vault access requestsOrganizationaccess:read—
POST/v1/access-requests/{request_id}/approveApprove a vault requestOrganizationaccess:write—
POST/v1/access-requests/{request_id}/denyDeny a vault requestOrganizationaccess:write—
GET/v1/external-sharesExternal sharing requestsOrganizationsharing:read1.2
POST/v1/external-shares/{link_id}/approveApprove an external linkOrganizationsharing:write1.2
POST/v1/external-shares/{link_id}/denyDecline an external linkOrganizationsharing:write1.2
GET/v1/signature-requestsList signature requestsOrganizationdocuments:read1.6
POST/v1/documents/{document_id}/cancelCancel a signature requestOrganizationsignatures:write1.6
GET/v1/webhooks/eventsEvent catalogOrganizationwebhooks:read1.6
GET/v1/webhooksList webhooksOrganizationwebhooks:read1.6
POST/v1/webhooksCreate a webhookOrganizationwebhooks:write1.6
GET/v1/webhooks/{webhook_id}One webhookOrganizationwebhooks:read1.6
PATCH/v1/webhooks/{webhook_id}Change a webhookOrganizationwebhooks:write1.6
DELETE/v1/webhooks/{webhook_id}Delete a webhookOrganizationwebhooks:write1.6
POST/v1/webhooks/{webhook_id}/rotate-secretRotate the signing secretOrganizationwebhooks:write1.6
POST/v1/webhooks/{webhook_id}/testSend a testOrganizationwebhooks:write1.6
GET/v1/webhooks/{webhook_id}/deliveriesDelivery logOrganizationwebhooks:read1.6
POST/v1/webhooks/{webhook_id}/replayReplay eventsOrganizationwebhooks:write1.6
GET/v1/controllerComputers, groups and recent actionsOrganizationcontroller:read1.7
POST/v1/controller/jobsRun an action on computersOrganizationcontroller:write1.7
GET/v1/controller/jobs/{job_id}One action and its resultsOrganizationcontroller:read1.7
GET/v1/remoteSeats, devices and sessionsOrganizationremote:read1.7
POST/v1/remote/sessions/{session_id}/endEnd a sessionOrganizationremote:write1.7
GET/v1/remote/invitesList invite linksOrganizationremote:read1.7
POST/v1/remote/invitesCreate an invite linkOrganizationremote:write1.7
DELETE/v1/remote/invites/{invite_id}Revoke an invite linkOrganizationremote:write1.7
GET/v1/vaultsRead shared vaultsAgentAgent token—

What’s new in release 1.7

Run the Controller and Remote from your own tools, and call the Customer API with personal API keys. Create a Remote invite link when a ticket is opened and end a session from your helpdesk; read every managed computer and queue scans, locks, messages and updates from your RMM or ITSM; follow each action’s result per computer. Personal keys (pxu_…) are scoped, expiring and can be limited to IP addresses. Older keys keep working; add the controller:read, controller:write, remote:read or remote:write scope to a key to use the new endpoints.

Release history

Release 1.7: Controller and Remote, personal API keys, IP allowlists and test keysController endpoints for your IT tools: GET /v1/controller (computers, groups, actions), POST /v1/controller/jobs (scan, lock, message, sync or update computers; signed actions stay in the admin console) and GET /v1/controller/jobs/{id} with a result per computer. Remote endpoints for your helpdesk: GET /v1/remote (seats, devices, sessions), invite links (GET, POST and DELETE /v1/remote/invites) and POST /v1/remote/sessions/{id}/end. New scopes: controller:read, controller:write, remote:read and remote:write, and 21 more webhook events for the Controller and Remote. Personal API keys (pxu_…) for the Customer API: scoped (vault, sync, workspaces, access), expiring, revocable, made in Passkey-X → Developers, with GET /v1/me, /v1/api-keys and each key's activity. Personal and organization keys can be limited to IP addresses (403 ip_not_allowed elsewhere) and one-hour read-only test keys are one click away. Every call with a key is logged, and the owner is emailed the first time a key is used from a new IP address. Calls through passkey-x.com/api carry the caller's real, signed IP address.
Organization API 1.6: Signing API, webhook events and webhooks through the APIGET /v1/signature-requests (who still has to sign), POST /v1/documents/{id}/cancel, proof summaries (quantum-safe, passkey, read before signing, offline) on GET /v1/documents/{id}, a new document.signed event, the webhook event catalog (GET /v1/webhooks/events) with exact event subscriptions, and webhooks managed through the API: create, change events, pause, rotate the secret, test, delivery log and replay. New scopes: signatures:write, webhooks:read and webhooks:write.
Organization API 1.5: Logs, company devices and safer automationGET /v1/logs (audit events, sign-ins, API calls, emails and alerts with filters and cursor pages), the company profile, company devices and device codes, setting and stopping policies, blocking and unblocking members, cursor pages on every list, Idempotency-Key on writes and rate-limit headers. Every API call is now recorded in the organization's Logs.
Organization API 1.4: Security centerSign-in risk, incidents and device trust for your SIEM, SOAR or GRC tool. Needs the security:read scope.
Organization API 1.3: Storage, insights and documentsThe storage pool and Runway forecast, the Trust Index, the document register with Seal Chain verification, and the company group report.
Organization API 1.2: Business automationOnboarding, member security, external-sharing approvals, access handover, item timelines and policies.

Customer API

For apps and scripts acting as a signed-in person. Tenant and workspace permissions are enforced by Row Level Security, so a workspace or tenant ID never grants access by itself.

Base URL
https://passkey-x.com/api
Auth
Personal API key (pxu_…) or session token
Rate limit
120 requests per minute per key (or per account for a session)

System

  • GET/v1/healthCheck the API is upNeeds: None

    Liveness check. Needs no token.

    Response · 200
    {
      "status": "ok"
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/v1/health'
  • GET/v1/item-typesList item typesNeeds: Any key

    The encrypted item types the apps understand.

    Response · 200
    {
      "items": [
        {
          "id": "login",
          "schema_version": 1
        },
        {
          "id": "secure-note",
          "schema_version": 1
        },
        {
          "id": "api-key",
          "schema_version": 1
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/v1/item-types' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"

Account and API keys

  • GET/v1/meWho am INew in 1.7Needs: Any key

    Who the credential belongs to, the key's name, prefix and scopes (for a personal API key), the requests left this minute, and your_ip: the address the API sees, to put in a key's IP allowlist. With a session token instead of a key, it answers credential "session" and your email, and has no key object. A good first call.

    Response · 200 · X-RateLimit-Limit: 120, X-RateLimit-Remaining: 119
    {
      "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
      "credential": "personal_api_key",
      "your_ip": "203.0.113.24",
      "key": {
        "id": "0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d",
        "name": "Backup script",
        "prefix": "pxu_3f9a1c2e",
        "scopes": [
          "vault:read",
          "sync:read"
        ],
        "test": false,
        "expires_at": "2027-01-24T09:30:00Z"
      },
      "rate_limit": {
        "limit": 120,
        "remaining": 119,
        "window_seconds": 60
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/v1/me' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"
  • GET/v1/api-keysList your personal API keysNew in 1.7Needs: Any key

    Your personal API keys (never the secrets): scopes, IP allowlist, test flag, expiry, and when and from where each was last used.

    Response · 200
    {
      "keys": [
        {
          "id": "0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d",
          "name": "Backup script",
          "prefix": "pxu_3f9a1c2e",
          "scopes": [
            "sync:read",
            "vault:read"
          ],
          "allowed_cidrs": [
            "203.0.113.0/24"
          ],
          "is_test": false,
          "created_at": "2026-10-26T09:30:00Z",
          "expires_at": "2027-01-24T09:30:00Z",
          "last_used_at": "2026-10-26T09:30:00Z",
          "last_used_ip": "203.0.113.24",
          "revoked_at": null
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/v1/api-keys' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"
  • POST/v1/api-keysCreate a personal API keyNew in 1.7Needs: Session only

    Needs a signed-in session (with the second step if you use two-step verification); a key can't create keys. scopes: vault:read, vault:write, workspaces:read, access:read, access:write, sync:read. Up to 10 active keys, 1–365 days. allowed_ips: up to 20 addresses or CIDR ranges (empty = anywhere). test: true makes a read-only key that expires after one hour. The key is in the response once; Passkey-X keeps only a hash.

    Request body
    {
      "name": "Backup script",
      "scopes": [
        "vault:read",
        "sync:read"
      ],
      "expires_in_days": 90,
      "allowed_ips": [
        "203.0.113.0/24"
      ]
    }
    Response · 201
    {
      "id": "0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d",
      "key": "pxu_3f9a1c2e…(64 hex characters)",
      "prefix": "pxu_3f9a1c2e",
      "scopes": [
        "sync:read",
        "vault:read"
      ],
      "expires_at": "2027-01-24T09:30:00Z",
      "test": false,
      "note": "Shown once. Store it in a secret manager; Passkey-X keeps only a hash."
    }

    Notable errors: validation_failedlimit_reachedmfa_requiredsession_required

    cURL
    curl -sS -X POST 'https://passkey-x.com/api/v1/api-keys' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "name": "Backup script",
      "scopes": [
        "vault:read",
        "sync:read"
      ],
      "expires_in_days": 90,
      "allowed_ips": [
        "203.0.113.0/24"
      ]
    }'
  • PATCH/v1/api-keys/{key_id}Change a key's IP allowlistNew in 1.7Needs: Session only

    Replaces the key's IP allowlist (up to 20 addresses or CIDR ranges; [] allows every address). Needs a signed-in session.

    ParameterInTypeDescription
    key_idrequiredpathuuidThe key.
    Request body
    {
      "allowed_ips": [
        "203.0.113.24",
        "198.51.100.0/24"
      ]
    }
    Response · 200
    {
      "id": "0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d",
      "allowed_ips": [
        "203.0.113.24/32",
        "198.51.100.0/24"
      ]
    }
    cURL
    curl -sS -X PATCH 'https://passkey-x.com/api/v1/api-keys/0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "allowed_ips": [
        "203.0.113.24",
        "198.51.100.0/24"
      ]
    }'
  • DELETE/v1/api-keys/{key_id}Revoke a personal API keyNew in 1.7Needs: Any key

    Revokes the key at once. With a session you can revoke any of your keys; a key can revoke only itself (handy when it may have leaked).

    ParameterInTypeDescription
    key_idrequiredpathuuidThe key.
    Response · 204

    No body.

    cURL
    curl -sS -X DELETE 'https://passkey-x.com/api/v1/api-keys/0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"
  • GET/v1/api-keys/{key_id}/activityA key's recent calls and addressesNew in 1.7Needs: Any key

    The key's latest calls (method, endpoint with ids as {id}, status, duration, IP, request id) and every address it was used from, plus 24-hour totals. Kept 90 days.

    ParameterInTypeDescription
    key_idrequiredpathuuidThe key.
    limitqueryinteger1–200 (default 50).
    Response · 200
    {
      "requests": [
        {
          "key_id": "0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d",
          "method": "GET",
          "path": "/v1/vault-items",
          "status": 200,
          "duration_ms": 84,
          "ip": "203.0.113.24",
          "request_id": "6f1c…",
          "created_at": "2026-10-26T09:30:00Z"
        }
      ],
      "addresses": [
        {
          "key_id": "0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d",
          "ip": "203.0.113.24",
          "first_seen": "2026-10-26T09:30:00Z",
          "last_seen": "2026-10-26T09:30:00Z",
          "requests": 412
        }
      ],
      "last_24h": {
        "requests": 412,
        "errors": 3,
        "blocked": 0
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/v1/api-keys/0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d/activity?limit=50' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"

Workspaces

  • GET/v1/workspacesList your workspacesNeeds: workspaces:read

    Your active workspaces with your role in each. Names are end-to-end encrypted.

    Response · 200
    {
      "workspaces": [
        {
          "id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
          "tenant_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
          "kind": "shared",
          "suite": "business",
          "status": "active",
          "current_key_version": 1,
          "key_rotation_required": false,
          "encrypted_name": "\\x9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c",
          "name_nonce": "\\xa1a1a1a1a1a1a1a1a1a1a1a1",
          "name_aad_hash": "\\x5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d",
          "caller_role": "manager",
          "created_at": "2026-10-26T09:30:00Z",
          "updated_at": "2026-10-26T09:30:00Z"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/v1/workspaces' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"
  • GET/v1/workspaces/{workspace_id}/membersList workspace membersNeeds: workspaces:read

    Members of a workspace you belong to.

    ParameterInTypeDescription
    workspace_idrequiredpathuuidThe workspace.
    Response · 200
    {
      "members": [
        {
          "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
          "tenant_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
          "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
          "role": "editor",
          "status": "active",
          "created_at": "2026-10-26T09:30:00Z",
          "updated_at": "2026-10-26T09:30:00Z"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/v1/workspaces/3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c/members' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"

Vault items

  • GET/v1/vault-itemsList vault itemsNeeds: vault:read

    The current revision of each live item, newest first. Page with next_cursor while has_more is true.

    ParameterInTypeDescription
    workspace_idqueryuuidOnly this workspace (optional).
    limitqueryinteger1–200 (default 100).
    cursorquerystringnext_cursor from the previous page.
    Response · 200
    {
      "items": [
        {
          "id": "c0ffee00-1234-4abc-8def-0123456789ab",
          "tenant_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
          "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
          "content_type": "login",
          "schema_version": 1,
          "head_revision": 3,
          "key_version": 1,
          "nonce": "\\xa1a1a1a1a1a1a1a1a1a1a1a1",
          "ciphertext": "\\x9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c",
          "aad_hash": "\\x5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d",
          "updated_at": "2026-10-26T09:30:00Z"
        }
      ],
      "next_cursor": "eyJ1IjoiMjAyNi0xMC0yNlQwOTozMDowMFoiLCJpIjoiYzBmZmVlMDAifQ",
      "has_more": true
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/v1/vault-items?workspace_id=3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c&limit=100' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"
  • GET/v1/vault-items/{item_id}Get one itemNeeds: vault:read

    The current revision of one item. The ETag header holds its revision.

    ParameterInTypeDescription
    item_idrequiredpathuuidThe item.
    Response · 200 · ETag: "3"
    {
      "id": "c0ffee00-1234-4abc-8def-0123456789ab",
      "tenant_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
      "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
      "content_type": "login",
      "schema_version": 1,
      "head_revision": 3,
      "key_version": 1,
      "nonce": "\\xa1a1a1a1a1a1a1a1a1a1a1a1",
      "ciphertext": "\\x9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c",
      "aad_hash": "\\x5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d",
      "updated_at": "2026-10-26T09:30:00Z"
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/v1/vault-items/c0ffee00-1234-4abc-8def-0123456789ab' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"
  • POST/v1/vault-itemsCreate an encrypted itemNeeds: vault:write

    Encrypt in the client first. Binary fields are \x-prefixed hex. You choose the id, so a retried create returns 409 already_exists instead of a duplicate.

    Request body
    {
      "id": "c0ffee00-1234-4abc-8def-0123456789ab",
      "tenant_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
      "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
      "content_type": "login",
      "schema_version": 1,
      "nonce": "\\xa1a1a1a1a1a1a1a1a1a1a1a1",
      "ciphertext": "\\x9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c",
      "aad_hash": "\\x5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d"
    }
    Response · 201 · ETag: "1"
    {
      "id": "c0ffee00-1234-4abc-8def-0123456789ab",
      "head_revision": 1
    }

    Notable errors: already_existsvalidation_failedplaintext_rejected

    cURL
    curl -sS -X POST 'https://passkey-x.com/api/v1/vault-items' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "id": "c0ffee00-1234-4abc-8def-0123456789ab",
      "tenant_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
      "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
      "content_type": "login",
      "schema_version": 1,
      "nonce": "\\xa1a1a1a1a1a1a1a1a1a1a1a1",
      "ciphertext": "\\x9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c",
      "aad_hash": "\\x5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d"
    }'
  • PATCH/v1/vault-items/{item_id}Add a new revisionNeeds: vault:write

    Re-encrypt the item and send the new envelope with the current ETag as If-Match.

    ParameterInTypeDescription
    item_idrequiredpathuuidThe item.
    If-MatchrequiredheaderstringThe item's current ETag, for example "3". A stale value returns 412.
    Request body
    {
      "nonce": "\\xa1a1a1a1a1a1a1a1a1a1a1a1",
      "ciphertext": "\\x9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c",
      "aad_hash": "\\x5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d"
    }
    Response · 200 · ETag: "2"
    {
      "id": "c0ffee00-1234-4abc-8def-0123456789ab",
      "head_revision": 2
    }

    Notable errors: revision_conflict

    cURL
    curl -sS -X PATCH 'https://passkey-x.com/api/v1/vault-items/c0ffee00-1234-4abc-8def-0123456789ab' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY" \
      -H 'If-Match: "1"' \
      -H 'Content-Type: application/json' \
      --data '{
      "nonce": "\\xa1a1a1a1a1a1a1a1a1a1a1a1",
      "ciphertext": "\\x9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c",
      "aad_hash": "\\x5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d"
    }'
  • DELETE/v1/vault-items/{item_id}Delete an itemNeeds: vault:write

    Deletes the item (kept as a tombstone so other devices sync the deletion). Send the current ETag as If-Match.

    ParameterInTypeDescription
    item_idrequiredpathuuidThe item.
    If-MatchrequiredheaderstringThe item's current ETag, for example "3". A stale value returns 412.
    Response · 204

    No body.

    cURL
    curl -sS -X DELETE 'https://passkey-x.com/api/v1/vault-items/c0ffee00-1234-4abc-8def-0123456789ab' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY" \
      -H 'If-Match: "1"'

Sync

  • GET/v1/sync/changesRead the change feedNeeds: sync:read

    Metadata-only changes since cursor. Store the returned cursor and call again while has_more is true.

    ParameterInTypeDescription
    workspace_idrequiredqueryuuidThe workspace.
    cursorquerystringThe cursor from the previous call (default 0).
    limitqueryinteger1–500 (default 500).
    Response · 200
    {
      "changes": [
        {
          "sequence": 18342,
          "entity_type": "vault_item",
          "entity_id": "c0ffee00-1234-4abc-8def-0123456789ab",
          "operation": "update",
          "entity_version": 3,
          "occurred_at": "2026-10-26T09:30:00Z"
        }
      ],
      "cursor": "18342",
      "has_more": false
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/v1/sync/changes?workspace_id=3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c&cursor=0&limit=500' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"

Access requests and grants

  • GET/v1/missionsList missionsNeeds: access:read

    Active missions in a workspace (encrypted definitions).

    ParameterInTypeDescription
    workspace_idrequiredqueryuuidThe workspace.
    Response · 200
    {
      "missions": [
        {
          "id": "9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a",
          "tenant_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
          "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
          "status": "active",
          "definition_nonce": "\\xa1a1a1a1a1a1a1a1a1a1a1a1",
          "encrypted_definition": "\\x9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c",
          "definition_aad_hash": "\\x5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d",
          "mission_items": [
            {
              "item_id": "c0ffee00-1234-4abc-8def-0123456789ab",
              "sort_order": 0
            }
          ],
          "created_at": "2026-10-26T09:30:00Z"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/v1/missions?workspace_id=3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"
  • GET/v1/access-requestsList access requestsNeeds: access:read

    The newest 200 access requests in a workspace.

    ParameterInTypeDescription
    workspace_idrequiredqueryuuidThe workspace.
    Response · 200
    {
      "requests": [
        {
          "id": "9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a",
          "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
          "item_id": "c0ffee00-1234-4abc-8def-0123456789ab",
          "requested_scope": "reveal",
          "requested_duration_minutes": 60,
          "status": "pending",
          "expires_at": "2026-10-26T09:30:00Z",
          "created_at": "2026-10-26T09:30:00Z"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/v1/access-requests?workspace_id=3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"
  • POST/v1/access-requestsRequest accessNeeds: access:write

    Ask for time-limited access. requested_scope is use, reveal, edit or manage; requested_duration_minutes is 5–10080 (one week); expires_at (RFC 3339) is when the request lapses if nobody decides. You choose the id, so a retry is safe (409 already_exists). The purpose is encrypted with the workspace key.

    Request body
    {
      "id": "9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a",
      "tenant_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
      "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
      "item_id": "c0ffee00-1234-4abc-8def-0123456789ab",
      "requested_scope": "reveal",
      "purpose_nonce": "\\xa1a1a1a1a1a1a1a1a1a1a1a1",
      "encrypted_purpose": "\\x9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c",
      "purpose_aad_hash": "\\x5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d",
      "requested_duration_minutes": 60,
      "expires_at": "2026-10-26T10:30:00Z"
    }
    Response · 201
    {
      "id": "9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a",
      "status": "pending",
      "created_at": "2026-10-26T09:30:00Z"
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/v1/access-requests' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "id": "9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a",
      "tenant_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
      "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
      "item_id": "c0ffee00-1234-4abc-8def-0123456789ab",
      "requested_scope": "reveal",
      "purpose_nonce": "\\xa1a1a1a1a1a1a1a1a1a1a1a1",
      "encrypted_purpose": "\\x9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c",
      "purpose_aad_hash": "\\x5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d",
      "requested_duration_minutes": 60,
      "expires_at": "2026-10-26T10:30:00Z"
    }'
  • POST/v1/access-requests/{request_id}/decisionApprove or deny a requestNeeds: access:write

    Managers decide pending requests.

    ParameterInTypeDescription
    request_idrequiredpathuuidThe request.
    Request body
    {
      "decision": "approved"
    }
    Response · 200
    {
      "approval_id": "e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b",
      "decision": "approved"
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/v1/access-requests/9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a/decision' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "decision": "approved"
    }'
  • GET/v1/access-grantsList access grantsNeeds: access:read

    The newest 200 time-limited grants in a workspace.

    ParameterInTypeDescription
    workspace_idrequiredqueryuuidThe workspace.
    Response · 200
    {
      "grants": [
        {
          "id": "f0e1d2c3-b4a5-4968-8776-655443322110",
          "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
          "item_id": "c0ffee00-1234-4abc-8def-0123456789ab",
          "subject_identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
          "scope": "reveal",
          "starts_at": "2026-10-26T09:30:00Z",
          "expires_at": "2026-10-26T10:30:00Z",
          "status": "active"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/v1/access-grants?workspace_id=3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c' \
      -H "Authorization: Bearer $PASSKEY_X_PERSONAL_KEY"

Personal API key scopes (Customer API)

A personal key can hold any of these; /v1/me, /v1/item-types and /v1/api-keys need none. Up to 10 active keys (and 5 test keys) per person; 120 requests per minute per key.

ScopeAllows
vault:readRead encrypted vault items (list and get)
vault:writeCreate, update and delete encrypted vault items
workspaces:readYour vaults and their members
sync:readThe change feed
access:readMissions, access requests and grants
access:writeRequest access and decide requests

The old /v1/connectors/… and /v1/saas/… routes have been removed and now answer 410 gone. The web app also uses POST /billing (Paddle checkout and customer portal), POST /tenant-sms (Sent notification settings) and POST /account-lifecycle (guarded account deletion) under the same base URL; they are listed in the OpenAPI file. Binary fields are hex text that starts with \x (written \\x inside JSON).

Organization API

A REST API for HR systems, ITSM and ticketing tools, SIEMs, GRC platforms, Zapier and Make: audit events, alerts, members, onboarding, member security, handover, external-sharing approvals, policies, storage, insights, documents, sign-in risk, incidents, device trust, signature requests, webhooks, the Controller and Remote. Vault contents, passwords and encryption keys are never available through it.

Base URL
https://passkey-x.com/api/org
Auth
Organization API key (pxk_…)
Rate limit
300 requests per minute per key

Paths include the /v1 prefix, so GET /v1/me is https://passkey-x.com/api/org/v1/me. API keys are created in the Admin console by organizations on the Business or Enterprise plan; if the organization later leaves Business, Business-only endpoints (onboarding, member security, external shares, handover, company devices, policies, webhooks and the Controller) answer 403 plan_required. Remote endpoints need the Remote add-on (403 addon_required).

Key and audit

  • GET/v1/meDescribe this keyScope: —

    The key's ID and name, organization ID, scopes, whether it is a one-hour test key, API version and how many requests are left this minute. A good first call to test a key. A key with an IP allowlist answers 403 ip_not_allowed from anywhere else.

    Response · 200 · X-RateLimit-Limit: 300, X-RateLimit-Remaining: 299, X-Org-API-Version: 1.7
    {
      "key_id": "0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d",
      "name": "SIEM pull",
      "organization_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
      "scopes": [
        "audit:read",
        "members:read",
        "reports:read"
      ],
      "test": false,
      "api_version": "1.7",
      "rate_limit": {
        "limit": 300,
        "remaining": 299,
        "window_seconds": 60
      }
    }

    Notable errors: ip_not_allowed

    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/me' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/audit-eventsRead audit eventsScope: audit:read

    Tamper-evident audit events in sequence order. Pass next_after back as after (or next_cursor as cursor) while has_more is true.

    ParameterInTypeDescription
    afterqueryintegerReturn events after this sequence (default 0).
    cursorquerystringThe next_cursor of the previous page (use instead of offset).
    limitqueryinteger1–500 (default 100).
    Response · 200
    {
      "data": [
        {
          "sequence": 18342,
          "occurred_at": "2026-10-26T09:30:00Z",
          "action": "member.invited",
          "target_type": "scim_provisioned_users",
          "target_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
          "actor_identity_id": null,
          "metadata": {
            "via": "api"
          },
          "event_hash": "9a7f…"
        }
      ],
      "next_after": 18342,
      "next_cursor": null,
      "has_more": false
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/audit-events?after=0&limit=100' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/items/{item_id}/timelineWho used a passwordNew in 1.2Scope: audit:read

    Who showed, copied, filled in or changed one vault item, newest first. Metadata only: never the content.

    ParameterInTypeDescription
    item_idrequiredpathuuidThe vault item.
    limitqueryinteger1–300 (default 100).
    Response · 200
    {
      "data": {
        "item_id": "c0ffee00-1234-4abc-8def-0123456789ab",
        "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
        "content_type": "login",
        "events": [
          {
            "sequence": 18340,
            "action": "item.copied",
            "at": "2026-10-26T09:30:00Z",
            "actor_identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
            "by": "Ana Ruiz"
          }
        ]
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/items/c0ffee00-1234-4abc-8def-0123456789ab/timeline?limit=100' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"

Logs

  • GET/v1/logsRead logsNew in 1.5Scope: logs:read

    One list of audit events, member sign-ins, API calls, emails and security alerts, newest first. Filter by type, time range, person, level, status and text; pass next_cursor back as cursor while has_more is true. Ranges up to one year (default: the last 30 days).

    ParameterInTypeDescription
    typequerystringComma-separated: audit, sign_in, api, email, alert (default: all).
    fromquerydate-timeStart (ISO 8601). Default: 30 days before to.
    toquerydate-timeEnd (ISO 8601). Default: now.
    actorqueryuuidOnly rows by this member (identity_id).
    levelquerystringinfo, warning or error.
    statusquerystringExact status, e.g. 422 for API calls, failed for emails, open for alerts.
    qquerystringText search in action, target, summary and person name (up to 100 characters).
    cursorquerystringnext_cursor from the previous page.
    limitqueryinteger1–200 (default 50).
    Response · 200
    {
      "data": [
        {
          "id": "api:8812",
          "type": "api",
          "occurred_at": "2026-10-26T09:30:00Z",
          "actor_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
          "actor": "Ana Ruiz",
          "action": "POST /v1/company/device-codes",
          "target": "HR automation",
          "level": "info",
          "status": "201",
          "summary": "POST /v1/company/device-codes → 201 (48 ms)",
          "details": {
            "method": "POST",
            "path": "/v1/company/device-codes",
            "status": 201,
            "duration_ms": 48,
            "ip": "203.0.113.9"
          }
        },
        {
          "id": "audit:10442",
          "type": "audit",
          "occurred_at": "2026-10-26T09:30:00Z",
          "actor_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
          "actor": "Ana Ruiz",
          "action": "member.blocked",
          "target": "Sam Lee",
          "level": "warning",
          "status": "recorded",
          "summary": "member.blocked",
          "details": {
            "reason": "Laptop stolen"
          }
        }
      ],
      "has_more": true,
      "next_cursor": "MjAyNi0xMC0yNlQwOTozMDowMC4wMDAwMDBafGF1ZGl0OjEwNDQy",
      "from": "2026-09-26T09:30:00Z",
      "to": "2026-10-26T09:30:00Z"
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/logs?type=audit%2Capi&from=2026-10-01T00%3A00%3A00Z&limit=50' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"

Alerts, reports and policies

  • GET/v1/alertsList security alertsScope: alerts:read

    Security alerts, newest first.

    ParameterInTypeDescription
    statusqueryenumopen, acknowledged or resolved.
    limitqueryinteger1–200 (default 50).
    sincequerydate-timeOnly rows created at or after this time (ISO 8601), for example 2026-10-01.
    untilquerydate-timeOnly rows created before this time (ISO 8601).
    qquerystringText search across the row (up to 100 characters).
    cursorquerystringThe next_cursor of the previous page (use instead of offset).
    Response · 200
    {
      "data": [
        {
          "id": "d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f7a",
          "severity": "high",
          "kind": "breach_exposure",
          "title": "3 passwords found in a new breach",
          "status": "open",
          "created_at": "2026-10-26T09:30:00Z",
          "acknowledged_at": null,
          "actor_identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/alerts?status=open&limit=50' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • PATCH/v1/alerts/{alert_id}Update an alertScope: alerts:write

    Acknowledge, resolve or reopen an alert, for example from your ticket system.

    ParameterInTypeDescription
    alert_idrequiredpathuuidThe alert.
    Request body
    {
      "status": "resolved",
      "note": "Passwords rotated (INC-4411)"
    }
    Response · 200
    {
      "data": {
        "id": "d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f7a",
        "status": "resolved"
      }
    }
    cURL
    curl -sS -X PATCH 'https://passkey-x.com/api/org/v1/alerts/d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f7a' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "status": "resolved",
      "note": "Passwords rotated (INC-4411)"
    }'
  • GET/v1/security/summarySecurity summaryScope: reports:read

    The organization's current security score, adoption and top risks.

    Response · 200
    {
      "data": {
        "generated_at": "2026-10-26T09:30:00Z",
        "members": 212,
        "members_reporting": 198,
        "score": 86,
        "score_week_ago": 82,
        "weak": 14,
        "reused": 9,
        "breached": 3,
        "two_step_pct": 94,
        "passkey_pct": 61,
        "alerts_open": 2,
        "top_risks": [
          {
            "key": "breached_passwords",
            "count": 3
          }
        ]
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/security/summary' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/reports/weeklyWeekly reportsScope: reports:read

    Stored weekly security reports, newest first.

    ParameterInTypeDescription
    limitqueryinteger1–52 (default 4).
    sincequerydate-timeOnly rows created at or after this time (ISO 8601), for example 2026-10-01.
    untilquerydate-timeOnly rows created before this time (ISO 8601).
    qquerystringText search across the row (up to 100 characters).
    cursorquerystringThe next_cursor of the previous page (use instead of offset).
    Response · 200
    {
      "data": [
        {
          "week_start": "2026-10-19",
          "report": {
            "score": 86,
            "members": 212
          },
          "ai_summary": null
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/reports/weekly?limit=4' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/policiesList security policiesNew in 1.2Scope: policies:read

    Every enforced and draft policy with its scope (organization, department or team) — for compliance evidence and drift checks.

    Response · 200
    {
      "data": [
        {
          "id": "c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f",
          "type": "external_sharing",
          "scope_type": "tenant",
          "scope_id": null,
          "configuration": {
            "mode": "approval",
            "require_reason": true,
            "max_hours": 72
          },
          "enforced": true,
          "priority": 100,
          "version": 2,
          "updated_at": "2026-10-26T09:30:00Z"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/policies' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • PUT/v1/policies/{policy_type}Set and enforce a policyNew in 1.5Scope: policies:write

    Creates or replaces the organization-wide value of a policy and enforces it (enforced: false keeps it as a draft). The configuration is checked like in the admin console; an invalid one answers 400. Types include session_rules, network_access, company_devices, external_sharing, behavior_guard and trusted_access.

    ParameterInTypeDescription
    policy_typerequiredpathstringThe policy type.
    Request body
    {
      "configuration": {
        "max_session_hours": 12
      },
      "enforced": true
    }
    Response · 200
    {
      "data": {
        "id": "c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f",
        "type": "session_rules",
        "configuration": {
          "max_session_hours": 12
        },
        "enforced": true,
        "version": 3,
        "updated_at": "2026-10-26T09:30:00Z"
      }
    }
    cURL
    curl -sS -X PUT 'https://passkey-x.com/api/org/v1/policies/session_rules' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "configuration": {
        "max_session_hours": 12
      },
      "enforced": true
    }'
  • DELETE/v1/policies/{policy_type}Stop enforcing a policyNew in 1.5Scope: policies:write

    Keeps the configuration but stops enforcing it. PUT it again to enforce.

    ParameterInTypeDescription
    policy_typerequiredpathstringThe policy type.
    Response · 200
    {
      "data": {
        "id": "c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f",
        "type": "network_access",
        "configuration": {
          "ip_ranges": [
            "203.0.113.0/24"
          ],
          "hours_enabled": false,
          "days": [
            1,
            2,
            3,
            4,
            5
          ],
          "start": "08:00",
          "end": "20:00",
          "time_zone": "UTC"
        },
        "enforced": false,
        "version": 4,
        "updated_at": "2026-10-26T09:30:00Z"
      }
    }
    cURL
    curl -sS -X DELETE 'https://passkey-x.com/api/org/v1/policies/network_access' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"

Storage, insights and documents

  • GET/v1/storageStorage reportNew in 1.3Scope: storage:read

    The organization's storage pool (plan amount, storage packs, space moved in or out by its company group), usage by vault, department and person, the 90-day trend and the Runway forecast of when it fills up.

    Response · 200
    {
      "data": {
        "allocated": 21474836480,
        "used": 1073741824,
        "files": 412,
        "percent": 5,
        "allocation": {
          "base": 21474836480,
          "packs": 0,
          "pack_count": 0,
          "moved_in": 0,
          "moved_out": 0,
          "total": 21474836480
        },
        "runway": {
          "points": 31,
          "growth_bytes_per_day": 31457280,
          "days_until_full": 648,
          "full_on": "2028-08-04",
          "r2": 1,
          "confidence": "high",
          "status": "healthy"
        },
        "by_department": [
          {
            "department_id": null,
            "name": "Company-wide",
            "bytes": 1073741824,
            "files": 412
          }
        ]
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/storage' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/insightsInsights and Trust IndexNew in 1.3Scope: insights:read

    The Passkey-X Trust Index (0–100, grade A–F) with its five parts, shared vaults that depend on one manager, the people whose departure would hurt most, access nobody used for 90 days, and actions ranked by the points they add.

    Response · 200
    {
      "data": {
        "trust_index": 78,
        "grade": "B",
        "components": {
          "strong_auth": {
            "score": 92,
            "weight": 30,
            "covered": 195,
            "total": 212
          }
        },
        "actions": [
          {
            "kind": "bus_factor",
            "count": 6,
            "points": 4.8,
            "text": "6 shared vaults depend on one manager: add a second"
          }
        ],
        "departure_impact": [
          {
            "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
            "name": "Ana Ruiz",
            "score": 100,
            "credentials_to_rotate": 184,
            "sole_holder_items": 12,
            "vaults": 9
          }
        ]
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/insights' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/documentsDocument registerNew in 1.3Scope: documents:read

    Signature requests and recorded signed documents with status, signer progress and expiry. Vault contents are never included.

    ParameterInTypeDescription
    statusquerystringpending, sealed, declined, revoked, lapsed or expired.
    offsetqueryintegerRows to skip (default 0).
    limitqueryinteger1–500 (default 100).
    cursorquerystringThe next_cursor of the previous page (use instead of offset).
    Response · 200
    {
      "data": {
        "esign": true,
        "summary": {
          "total": 42,
          "pending": 3,
          "sealed": 30,
          "recorded": 7,
          "expiring_30": 2
        },
        "rows": [
          {
            "id": "e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a8b",
            "label": "Supplier NDA",
            "doc_type": "nda",
            "kind": "seal",
            "status": "sealed",
            "expires_on": "2027-10-01",
            "days_left": 353,
            "signers_total": 2,
            "signers_signed": 2,
            "verify_code": "PX-7K2M-QW9D-HT4R-B8NC"
          }
        ]
      },
      "next_offset": 1,
      "has_more": false
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/documents?status=sealed&offset=0&limit=100' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/documents/{document_id}One documentNew in 1.3Scope: documents:read

    Signers (with public keys and ECDSA P-256 signatures), evidence for outside signers, the document's Seal Chain entries and (1.6) progress and a proof summary for every signature: quantum-safe ML-DSA-65, passkey or fingerprint, read before signing and offline signing.

    ParameterInTypeDescription
    document_idrequiredpathuuidThe document.
    Response · 200
    {
      "data": {
        "id": "e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a8b",
        "label": "Supplier NDA",
        "status": "sealed",
        "document_sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
        "signers": [
          {
            "kind": "external",
            "name": "Priya Shah",
            "email": "priya@customer.example",
            "status": "signed",
            "signed_at": "2026-10-26T09:30:00Z"
          }
        ],
        "ledger": [
          {
            "seq": 12,
            "event": "sealed",
            "anchored": true
          }
        ],
        "progress": {
          "signed": 1,
          "declined": 0,
          "waiting": 0,
          "total": 1
        },
        "can_cancel": false,
        "proofs": [
          {
            "signer_id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
            "position": 1,
            "signed_at": "2026-10-26T09:30:00Z",
            "version": 2,
            "quantum_safe": true,
            "quantum_safe_algorithm": "ML-DSA-65",
            "passkey": "webauthn",
            "passkey_registered": false,
            "read_before_signing": true,
            "reading": {
              "pages": 3,
              "total_seconds": 46,
              "all_pages": true
            },
            "offline": false,
            "offline_signed_at": null,
            "received_at": "2026-10-26T09:30:00Z"
          }
        ]
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/documents/e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a8b' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/documents/verifyVerify a documentNew in 1.3Scope: documents:read

    Checks a file against its verify code. Send the code and the SHA-256 of the file; a code on its own reveals nothing.

    Request body
    {
      "code": "PX-7K2M-QW9D-HT4R-B8NC",
      "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
    }
    Response · 200
    {
      "data": {
        "valid": true,
        "status": "sealed",
        "label": "Supplier NDA",
        "signers": [
          {
            "name": "Priya Shah",
            "status": "signed"
          }
        ]
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/documents/verify' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "code": "PX-7K2M-QW9D-HT4R-B8NC",
      "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
    }'
  • GET/v1/company-group/reportCompany group reportNew in 1.3Scope: reports:read

    For the parent organization of a company group: every organization's plan, seats, members, vaults, storage, onboarding, open alerts, documents and Trust Index, with totals.

    Response · 200
    {
      "data": {
        "group": {
          "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
          "name": "Acme Holdings"
        },
        "totals": {
          "organizations": 3,
          "seats": 400,
          "members": 352,
          "allocated": 858993459200,
          "used": 64424509440,
          "trust_index": 81
        },
        "organizations": [
          {
            "tenant_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
            "label": "Acme India",
            "is_parent": true,
            "plan": "business",
            "seats": 200,
            "trust_index": 84,
            "grade": "B"
          }
        ]
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/company-group/report' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"

Security center

  • GET/v1/securitySecurity summaryNew in 1.4Scope: security:read

    Sign-ins scored by the Passkey-X Sign-in Risk model (medium and high), open and resolved incidents, and the device trust mode.

    ParameterInTypeDescription
    daysqueryintegerWindow, 1 to 90 days.
    Response · 200
    {
      "data": {
        "days": 30,
        "sign_in_risk": {
          "sign_ins": 1840,
          "medium": 41,
          "high": 3
        },
        "incidents": {
          "open": 1,
          "in_progress": 2,
          "resolved": 9
        },
        "device_trust": {
          "mode": "block"
        }
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/security?days=30' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/incidentsIncidentsNew in 1.4Scope: security:read

    Security incidents with their playbook (compromised account, lost device, departed employee, phishing click, breach exposure, insider risk) and checklist progress.

    ParameterInTypeDescription
    statusquerystringopen, in_progress or resolved.
    offsetqueryintegerRows to skip (default 0).
    limitqueryinteger1–500 (default 100).
    cursorquerystringThe next_cursor of the previous page (use instead of offset).
    Response · 200
    {
      "data": {
        "rows": [
          {
            "id": "e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a8b",
            "playbook": "lost_device",
            "title": "Laptop left on a train",
            "severity": "high",
            "status": "in_progress",
            "automatic": false,
            "steps_done": 2,
            "steps_total": 5,
            "created_at": "2026-10-26T09:30:00Z"
          }
        ]
      },
      "next_offset": 1,
      "has_more": false
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/incidents?status=open&offset=0&limit=100' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/device-trustDevice trustNew in 1.4Scope: security:read

    Every member device seen in the last 90 days, checked against the organization's device trust policy and the minimum supported app versions.

    Response · 200
    {
      "data": {
        "rows": [
          {
            "device_id": "e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a8b",
            "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
            "platform": "android",
            "app_version": "1.3.0",
            "verdict": "block",
            "mode": "block",
            "reasons": [
              {
                "id": "app_version",
                "text": "Update Passkey-X to 1.4.0 or later."
              }
            ]
          }
        ]
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/device-trust' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"

Company profile and devices

  • GET/v1/companyCompany profileNew in 1.5Scope: company:read

    Company name, logo, colour and sign-in message, the company address (name.passkey-x.com and your own domain) and the access rules: company devices only, office network and working hours, session length and trusted locations.

    Response · 200
    {
      "data": {
        "organization_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
        "name": "Acme Corp",
        "logo": "data:image/webp;base64,UklGR…",
        "accent_color": "#1d4ed8",
        "sign_in_message": "Use your Acme email.",
        "address": "acme.passkey-x.com",
        "custom_domain": "vault.acme.com",
        "custom_domain_verified": true,
        "access_rules": {
          "company_devices": {
            "configuration": {
              "mode": "enrolled",
              "desktop_only": false
            },
            "enforced": true,
            "updated_at": "2026-10-26T09:30:00Z"
          },
          "session_rules": {
            "configuration": {
              "max_session_hours": 12
            },
            "enforced": true,
            "updated_at": "2026-10-26T09:30:00Z"
          }
        },
        "updated_at": "2026-10-26T09:30:00Z"
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/company' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/company/devicesCompany devices and codesNew in 1.5Scope: company:read

    Devices enrolled for members (platform, OS, enrolled and last used) and the device codes issued in the last 200, with their status: open, used, expired or cancelled. Codes themselves are never returned.

    ParameterInTypeDescription
    include_removedquerybooleantrue to include removed devices.
    Response · 200
    {
      "data": {
        "devices": [
          {
            "id": "e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a8b",
            "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
            "name": "Ana Ruiz",
            "label": "ThinkPad 1042",
            "platform": "desktop",
            "os": "Windows",
            "enrolled_at": "2026-10-26T09:30:00Z",
            "last_seen_at": "2026-10-26T09:30:00Z",
            "removed_at": null
          }
        ],
        "codes": [
          {
            "id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
            "email": "ana@example.com",
            "label": "ThinkPad 1042",
            "created_at": "2026-10-26T09:30:00Z",
            "expires_at": "2026-10-26T09:30:00Z",
            "used_at": "2026-10-26T09:30:00Z",
            "cancelled_at": null,
            "status": "used"
          }
        ]
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/company/devices?include_removed=false' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/company/device-codesIssue a device codeNew in 1.5Scope: devices:write

    Creates a one-time device code for a member's email and (by default) emails it to them. They enter it once on the company laptop. The code is returned once; only its hash is kept. Send an Idempotency-Key so a retry doesn't issue a second code.

    ParameterInTypeDescription
    Idempotency-Keyheaderstring8–128 characters; repeats within 24 hours return the first answer.
    Request body
    {
      "email": "ana@example.com",
      "label": "ThinkPad 1042",
      "hours": 72,
      "send_email": true
    }
    Response · 201
    {
      "data": {
        "id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
        "code": "PXD-7K2M-QW9D-HT4R",
        "email": "ana@example.com",
        "expires_at": "2026-10-26T09:30:00Z",
        "emailed": true
      }
    }

    Notable errors: conflict

    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/company/device-codes' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Idempotency-Key: hr-onboarding-10442' \
      -H 'Content-Type: application/json' \
      --data '{
      "email": "ana@example.com",
      "label": "ThinkPad 1042",
      "hours": 72,
      "send_email": true
    }'
  • DELETE/v1/company/devices/{device_id}Remove a company deviceNew in 1.5Scope: devices:write

    The device stops working for this organization at once (its sessions are signed out of the company rules). Enroll it again with a new code.

    ParameterInTypeDescription
    device_idrequiredpathuuidThe device.
    Response · 200
    {
      "data": {
        "id": "e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a8b",
        "removed_at": "2026-10-26T09:30:00Z"
      }
    }
    cURL
    curl -sS -X DELETE 'https://passkey-x.com/api/org/v1/company/devices/e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a8b' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • DELETE/v1/company/device-codes/{code_id}Cancel a device codeNew in 1.5Scope: devices:write

    An unused code stops working. Used codes can't be cancelled (remove the device instead).

    ParameterInTypeDescription
    code_idrequiredpathuuidThe code's id (not the code).
    Response · 200
    {
      "data": {
        "id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
        "cancelled_at": "2026-10-26T09:30:00Z"
      }
    }

    Notable errors: conflict

    cURL
    curl -sS -X DELETE 'https://passkey-x.com/api/org/v1/company/device-codes/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"

Members and onboarding

  • POST/v1/members/{identity_id}/blockBlock a memberNew in 1.5Scope: members:write

    Pauses the member's access to every vault of the organization and signs them out everywhere; roles and vault keys stay, so unblocking restores everything. Owners and admins can't be blocked through the API.

    ParameterInTypeDescription
    identity_idrequiredpathuuidThe member.
    Request body
    {
      "reason": "Laptop reported stolen"
    }
    Response · 200
    {
      "data": {
        "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
        "blocked": true,
        "sessions_signed_out": 2
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/members/5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9/block' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "reason": "Laptop reported stolen"
    }'
  • POST/v1/members/{identity_id}/unblockUnblock a memberNew in 1.5Scope: members:write

    Lifts a block (from the admin console or the API). changed is false when the member wasn't blocked.

    ParameterInTypeDescription
    identity_idrequiredpathuuidThe member.
    Response · 200
    {
      "data": {
        "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
        "blocked": false,
        "changed": true
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/members/5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9/unblock' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/membersList membersScope: members:read

    Members with name, email, role, two-step and passkey status and security score.

    ParameterInTypeDescription
    offsetqueryintegerRows to skip (default 0).
    limitqueryinteger1–500 (default 100).
    cursorquerystringThe next_cursor of the previous page (use instead of offset).
    Response · 200
    {
      "data": [
        {
          "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
          "role": "member",
          "status": "active",
          "display_name": "Ana Ruiz",
          "job_title": "Engineer",
          "email": "ana@example.com",
          "two_step": true,
          "passkey": true,
          "security_score": 91,
          "joined_at": "2026-10-26T09:30:00Z"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/members?offset=0&limit=100' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/membersInvite a memberScope: members:write

    Invites a person by email (safe to repeat). They join when they sign in with that verified email.

    Request body
    {
      "email": "ana@example.com",
      "display_name": "Ana Ruiz",
      "job_title": "Engineer",
      "external_id": "HR-10442"
    }
    Response · 201
    {
      "data": {
        "id": "e2f3a4b5-c6d7-4e8f-9a0b-1c2d3e4f5a6b",
        "email": "ana@example.com",
        "display_name": "Ana Ruiz",
        "job_title": "Engineer",
        "identity_id": null,
        "status": "invited",
        "created_at": "2026-10-26T09:30:00Z"
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/members' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "email": "ana@example.com",
      "display_name": "Ana Ruiz",
      "job_title": "Engineer",
      "external_id": "HR-10442"
    }'
  • POST/v1/members/{identity_id}/suspendSuspend a memberScope: members:write

    Ends their vault access now and flags affected vaults for key rotation.

    ParameterInTypeDescription
    identity_idrequiredpathuuidThe member.
    Response · 200
    {
      "data": {
        "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
        "role": "member",
        "status": "suspended"
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/members/5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9/suspend' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/members/{identity_id}/reactivateReactivate a memberScope: members:write

    Restores membership. Vault access must be shared again.

    ParameterInTypeDescription
    identity_idrequiredpathuuidThe member.
    Response · 200
    {
      "data": {
        "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
        "role": "member",
        "status": "active"
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/members/5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9/reactivate' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • DELETE/v1/members/{identity_id}Offboard a memberScope: members:write

    Suspends and deprovisions the member. Owners can't be changed through the API. Pair it with a handover so nothing is lost.

    ParameterInTypeDescription
    identity_idrequiredpathuuidThe member.
    Response · 200
    {
      "data": {
        "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
        "role": "member",
        "status": "suspended"
      }
    }
    cURL
    curl -sS -X DELETE 'https://passkey-x.com/api/org/v1/members/5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/invitationsList open invitationsScope: members:read

    People invited who haven't joined yet.

    ParameterInTypeDescription
    offsetqueryintegerRows to skip (default 0).
    limitqueryinteger1–500 (default 100).
    cursorquerystringThe next_cursor of the previous page (use instead of offset).
    Response · 200
    {
      "data": [
        {
          "id": "e2f3a4b5-c6d7-4e8f-9a0b-1c2d3e4f5a6b",
          "email": "ana@example.com",
          "display_name": "Ana Ruiz",
          "job_title": "Engineer",
          "external_id": "HR-10442",
          "active": true,
          "created_at": "2026-10-26T09:30:00Z"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/invitations?offset=0&limit=100' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • DELETE/v1/invitations/{invitation_id}Cancel an invitationScope: members:write

    Cancels an invitation that hasn't been accepted.

    ParameterInTypeDescription
    invitation_idrequiredpathuuidThe invitation.
    Response · 204

    No body.

    cURL
    curl -sS -X DELETE 'https://passkey-x.com/api/org/v1/invitations/e2f3a4b5-c6d7-4e8f-9a0b-1c2d3e4f5a6b' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/onboardingOnboarding progressNew in 1.2Scope: onboarding:read

    Every Onboarding Vault plan with its steps and progress. Step titles only — the starting passwords stay end-to-end encrypted.

    ParameterInTypeDescription
    statusqueryenuminvited, active, completed, overdue, paused or cancelled.
    offsetqueryintegerRows to skip (default 0).
    limitqueryinteger1–200 (default 50).
    cursorquerystringThe next_cursor of the previous page (use instead of offset).
    Response · 200
    {
      "data": [
        {
          "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
          "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
          "label": "Ana Ruiz",
          "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
          "status": "overdue",
          "mode": "mandatory",
          "due_at": "2026-10-26T09:30:00Z",
          "created_at": "2026-10-26T09:30:00Z",
          "started_at": "2026-10-26T09:30:00Z",
          "completed_at": null,
          "last_reminded_at": null,
          "reminders": 0,
          "steps_total": 4,
          "steps_done": 2,
          "steps": [
            {
              "id": "0b1c2d3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
              "title": "Microsoft 365",
              "kind": "credential",
              "change_required": true,
              "done_at": "2026-10-26T09:30:00Z",
              "rotated_at": "2026-10-26T09:30:00Z"
            }
          ],
          "waiting_for_key": false
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/onboarding?status=overdue&offset=0&limit=50' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/onboarding/{plan_id}/remindSend a reminderNew in 1.2Scope: onboarding:write

    Emails the new hire about the steps left. At most one reminder per hour; they must have joined.

    ParameterInTypeDescription
    plan_idrequiredpathuuidThe onboarding plan.
    Response · 200
    {
      "data": {
        "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
        "status": "active",
        "due_at": "2026-10-26T09:30:00Z",
        "last_reminded_at": "2026-10-26T09:30:00Z",
        "reminders": 1
      }
    }

    Notable errors: conflict

    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/onboarding/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/remind' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/onboarding/{plan_id}/extendExtend the deadlineNew in 1.2Scope: onboarding:write

    Moves the deadline later by days (1–90, default 7) and lifts an overdue pause.

    ParameterInTypeDescription
    plan_idrequiredpathuuidThe onboarding plan.
    Request body
    {
      "days": 7
    }
    Response · 200
    {
      "data": {
        "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
        "status": "active",
        "due_at": "2026-11-02T09:30:00Z",
        "last_reminded_at": null,
        "reminders": 0
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/onboarding/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/extend' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "days": 7
    }'
  • POST/v1/onboarding/{plan_id}/resumeResume paused onboardingNew in 1.2Scope: onboarding:write

    Restores vault access paused for an overdue onboarding and gives days more (default 7).

    ParameterInTypeDescription
    plan_idrequiredpathuuidThe onboarding plan.
    Request body
    {
      "days": 3
    }
    Response · 200
    {
      "data": {
        "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
        "status": "active",
        "due_at": "2026-10-29T09:30:00Z",
        "last_reminded_at": null,
        "reminders": 0
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/onboarding/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/resume' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "days": 3
    }'
  • POST/v1/onboarding/{plan_id}/cancelCancel onboardingNew in 1.2Scope: onboarding:write

    Cancels the plan, for example when an offer is withdrawn.

    ParameterInTypeDescription
    plan_idrequiredpathuuidThe onboarding plan.
    Response · 200
    {
      "data": {
        "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
        "status": "cancelled",
        "due_at": "2026-10-26T09:30:00Z",
        "last_reminded_at": null,
        "reminders": 0
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/onboarding/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d/cancel' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/member-securityMember security for auditsNew in 1.2Scope: reports:read

    Per-member vault health (counts only), device checks from the last 90 days, two-step and onboarding. Each export is audited.

    ParameterInTypeDescription
    offsetqueryintegerRows to skip (default 0).
    limitqueryinteger1–500 (default 100).
    cursorquerystringThe next_cursor of the previous page (use instead of offset).
    Response · 200
    {
      "data": [
        {
          "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
          "name": "Ana Ruiz",
          "email": "ana@example.com",
          "role": "member",
          "two_step": true,
          "last_sign_in_at": "2026-10-26T09:30:00Z",
          "health": {
            "score": 91,
            "logins": 142,
            "weak": 1,
            "reused": 0,
            "old": 4,
            "breached": 0,
            "missing_totp": 6,
            "passkeys": 3,
            "reported_at": "2026-10-26T09:30:00Z"
          },
          "devices": [
            {
              "platform": "android",
              "os": "Android 15",
              "app_version": "1.0.2",
              "last_seen_at": "2026-10-26T09:30:00Z",
              "score": 100,
              "checks": {
                "screen_lock": true,
                "rooted": false,
                "work_profile": true
              }
            }
          ],
          "onboarding": {
            "status": "completed",
            "due_at": "2026-10-26T09:30:00Z",
            "left": 0
          }
        }
      ],
      "next_offset": 1,
      "has_more": false
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/member-security?offset=0&limit=100' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"

Access handover

  • GET/v1/handoversList handoversNew in 1.2Scope: handover:read

    Recent handovers with how many handed-over passwords the successor has already changed.

    ParameterInTypeDescription
    limitqueryinteger1–200 (default 50).
    sincequerydate-timeOnly rows created at or after this time (ISO 8601), for example 2026-10-01.
    untilquerydate-timeOnly rows created before this time (ISO 8601).
    qquerystringText search across the row (up to 100 characters).
    cursorquerystringThe next_cursor of the previous page (use instead of offset).
    Response · 200
    {
      "data": [
        {
          "id": "f1e2d3c4-b5a6-4978-8695-a4b3c2d1e0f9",
          "from_identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
          "from": "Ana Ruiz",
          "to_identity_id": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
          "to": "Raj Patel",
          "workspaces": 3,
          "items": 27,
          "items_rotated": 19,
          "note": "HR ticket 4411",
          "created_at": "2026-10-26T09:30:00Z"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/handovers?limit=50' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/handovers/previewPreview a handoverNew in 1.2Scope: handover:read

    The vaults the leaver owns or manages and the passwords they used in the last 90 days. Nothing changes.

    ParameterInTypeDescription
    fromrequiredqueryuuidThe leaver's identity_id.
    toqueryuuidThe successor's identity_id (optional).
    Response · 200
    {
      "data": {
        "from": "Ana Ruiz",
        "to": "Raj Patel",
        "workspaces": [
          {
            "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
            "role": "manager",
            "status": "active",
            "successor_role": null,
            "other_managers": 1
          }
        ],
        "items": [
          {
            "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
            "item_id": "c0ffee00-1234-4abc-8def-0123456789ab",
            "last_used_at": "2026-10-26T09:30:00Z",
            "uses": 12
          }
        ]
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/handovers/preview?from=5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9&to=7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/handoversHand over accessNew in 1.2Scope: handover:write

    Makes the successor a manager of every vault the leaver owns or manages and queues the passwords the leaver used for rotation. Vault keys are delivered from an administrator's device (Sharing & bundles), so access is end-to-end encrypted.

    Request body
    {
      "from_identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
      "to_identity_id": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
      "note": "HR ticket 4411"
    }
    Response · 201
    {
      "data": {
        "id": "f1e2d3c4-b5a6-4978-8695-a4b3c2d1e0f9",
        "from_identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
        "to_identity_id": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
        "workspaces": 3,
        "items": 27,
        "created_at": "2026-10-26T09:30:00Z"
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/handovers' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "from_identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
      "to_identity_id": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
      "note": "HR ticket 4411"
    }'

Vaults, sharing and access

  • GET/v1/workspacesList shared vaultsScope: workspaces:read

    Shared vaults with kind, request label, member count and whether key rotation is due. Names are encrypted and never returned.

    Response · 200
    {
      "data": [
        {
          "id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
          "kind": "shared",
          "suite": "business",
          "status": "active",
          "request_label": "Finance",
          "key_rotation_required": false,
          "created_at": "2026-10-26T09:30:00Z",
          "members": 14
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/workspaces' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/groupsList directory groupsScope: groups:read

    SCIM groups with member counts and the vaults each group maps to.

    Response · 200
    {
      "data": [
        {
          "id": "4a5b6c7d-8e9f-4a0b-9c1d-2e3f4a5b6c7d",
          "display_name": "Finance",
          "external_id": "okta-00g1",
          "created_at": "2026-10-26T09:30:00Z",
          "members": 14,
          "workspaces": [
            {
              "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
              "role": "editor"
            }
          ]
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/groups' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/access-requestsList vault access requestsScope: access:read

    Requests for shared vaults with the reason and requested duration.

    ParameterInTypeDescription
    statusqueryenumpending, approved, denied or cancelled.
    limitqueryinteger1–200 (default 50).
    sincequerydate-timeOnly rows created at or after this time (ISO 8601), for example 2026-10-01.
    untilquerydate-timeOnly rows created before this time (ISO 8601).
    qquerystringText search across the row (up to 100 characters).
    cursorquerystringThe next_cursor of the previous page (use instead of offset).
    Response · 200
    {
      "data": [
        {
          "id": "9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a",
          "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
          "label": "Finance",
          "requester_identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
          "requester_name": "Ana Ruiz",
          "role": "viewer",
          "reason": "Quarter close",
          "duration_hours": 8,
          "status": "pending",
          "decided_via": null,
          "decision_note": null,
          "access_expires_at": null,
          "created_at": "2026-10-26T09:30:00Z",
          "decided_at": null
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/access-requests?status=pending&limit=50' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/access-requests/{request_id}/approveApprove a vault requestScope: access:write

    Approves; time-limited access ends automatically. A vault owner's device delivers the key.

    ParameterInTypeDescription
    request_idrequiredpathuuidThe request.
    Request body
    {
      "note": "Approved by the Service Desk (ticket INC-4411)"
    }
    Response · 200
    {
      "data": {
        "id": "9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a",
        "status": "approved",
        "access_expires_at": "2026-10-26T17:30:00Z"
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/access-requests/9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a/approve' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "note": "Approved by the Service Desk (ticket INC-4411)"
    }'
  • POST/v1/access-requests/{request_id}/denyDeny a vault requestScope: access:write

    Declines the request.

    ParameterInTypeDescription
    request_idrequiredpathuuidThe request.
    Request body
    {
      "note": "Declined by the Service Desk (ticket INC-4411)"
    }
    Response · 200
    {
      "data": {
        "id": "9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a",
        "status": "denied",
        "access_expires_at": null
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/access-requests/9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a/deny' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "note": "Declined by the Service Desk (ticket INC-4411)"
    }'
  • GET/v1/external-sharesExternal sharing requestsNew in 1.2Scope: sharing:read

    Secure Send links to people outside the organization that need (or had) approval: who, why, for whom, size and expiry — never the content.

    ParameterInTypeDescription
    statusqueryenumpending, approved or denied.
    limitqueryinteger1–200 (default 50).
    sincequerydate-timeOnly rows created at or after this time (ISO 8601), for example 2026-10-01.
    untilquerydate-timeOnly rows created before this time (ISO 8601).
    qquerystringText search across the row (up to 100 characters).
    cursorquerystringThe next_cursor of the previous page (use instead of offset).
    Response · 200
    {
      "data": [
        {
          "id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
          "sender_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
          "sender": "Ana Ruiz",
          "kind": "text",
          "byte_size": 312,
          "reason": "Vendor onboarding",
          "recipient": "vendor@partner.example",
          "max_views": 1,
          "passphrase": true,
          "created_at": "2026-10-26T09:30:00Z",
          "expires_at": "2026-10-27T09:30:00Z",
          "status": "pending",
          "decided_at": null,
          "decided_by": null,
          "note": null
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/external-shares?status=pending&limit=50' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/external-shares/{link_id}/approveApprove an external linkNew in 1.2Scope: sharing:write

    The recipient can open the link from now on. The sender is emailed.

    ParameterInTypeDescription
    link_idrequiredpathuuidThe Secure Send link.
    Request body
    {
      "note": "Approved for this vendor"
    }
    Response · 200
    {
      "data": {
        "id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
        "status": "approved",
        "decided_at": "2026-10-26T09:30:00Z"
      }
    }

    Notable errors: conflict

    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/external-shares/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/approve' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "note": "Approved for this vendor"
    }'
  • POST/v1/external-shares/{link_id}/denyDecline an external linkNew in 1.2Scope: sharing:write

    Declines the link and deletes its encrypted content. The sender is emailed with your note.

    ParameterInTypeDescription
    link_idrequiredpathuuidThe Secure Send link.
    Request body
    {
      "note": "Use the vendor portal instead"
    }
    Response · 200
    {
      "data": {
        "id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
        "status": "denied",
        "decided_at": "2026-10-26T09:30:00Z"
      }
    }

    Notable errors: conflict

    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/external-shares/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e/deny' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "note": "Use the vendor portal instead"
    }'

Signatures

  • GET/v1/signature-requestsList signature requestsNew in 1.6Scope: documents:read

    Requests sent for signature, newest first, with how many have signed and who is still to sign (and whether they opened it). Filter pending ones to chase signers from your contract or HR system.

    ParameterInTypeDescription
    statusquerystringpending, sealed, declined, revoked, lapsed or expired.
    limitqueryinteger1–500 (default 100).
    Response · 200
    {
      "data": [
        {
          "id": "e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a8b",
          "label": "Offer letter",
          "doc_type": "contract",
          "status": "pending",
          "cancelled": false,
          "signing_order": "sequential",
          "verify_code": "PX-7K2M-QW9D-HT4R-B8NC",
          "created_by_name": "Ravi Kumar",
          "created_at": "2026-10-26T09:30:00Z",
          "request_deadline": null,
          "signed": 1,
          "total": 2,
          "waiting_for": [
            {
              "signer_id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
              "kind": "external",
              "position": 2,
              "status": "pending",
              "name": "Priya Shah",
              "viewed_at": "2026-10-26T09:30:00Z"
            }
          ]
        }
      ],
      "has_more": false,
      "next_cursor": null
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/signature-requests?status=pending&limit=100' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/documents/{document_id}/cancelCancel a signature requestNew in 1.6Scope: signatures:write

    Cancels a pending request: outside signers' links stop working, their copy of the document is deleted, and members see it as cancelled. Recorded in the Seal Chain and the audit log (document.request_cancelled) as the key's owner.

    ParameterInTypeDescription
    document_idrequiredpathuuidThe signature request.
    Request body
    {
      "reason": "Replaced by version 2"
    }
    Response · 200
    {
      "data": {
        "id": "e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a8b",
        "status": "revoked",
        "cancelled": true,
        "revoked_at": "2026-10-26T09:30:00Z",
        "reason": "Replaced by version 2"
      }
    }

    Notable errors: conflict

    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/documents/e5f6a7b8-c9d0-4e1f-9a2b-3c4d5e6f7a8b/cancel' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "reason": "Replaced by version 2"
    }'

Webhooks

  • GET/v1/webhooks/eventsEvent catalogNew in 1.6Scope: webhooks:read

    Every event a webhook can subscribe to, with its category. A filter that names one of these events matches that event only; any other filter (such as member.) is a prefix.

    Response · 200
    {
      "data": [
        {
          "event": "document.signed",
          "category": "documents",
          "description": "A signer signed a document (with the proof summary)"
        },
        {
          "event": "security_alert.raised",
          "category": "security",
          "description": "A security alert was raised"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/webhooks/events' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/webhooksList webhooksNew in 1.6Scope: webhooks:read

    The organization's webhooks and SIEM destinations (at most 5) with their events, health and last delivery. Secrets are never returned.

    Response · 200
    {
      "data": [
        {
          "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
          "name": "Contracts",
          "url": "https://contracts.example.com/passkey-x",
          "format": "generic",
          "events": [
            "document.sealed",
            "document.signed"
          ],
          "enabled": true,
          "created_at": "2026-10-26T09:30:00Z",
          "delivered_through": 18342,
          "failure_count": 0,
          "last_success_at": "2026-10-26T09:30:00Z",
          "last_status": 200,
          "last_error": null,
          "health": "delivering"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/webhooks' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/webhooksCreate a webhookNew in 1.6Scope: webhooks:write

    Creates an HTTPS webhook (public address only) that starts with the next event. The signing secret (pxwh_…) is returned once; an idempotent replay returns it as null. Leave events out to receive everything.

    ParameterInTypeDescription
    Idempotency-Keyheaderstring8–128 characters; repeats within 24 hours return the first answer (without the secret).
    Request body
    {
      "name": "Contracts",
      "url": "https://contracts.example.com/passkey-x",
      "events": [
        "document.signed",
        "document.declined",
        "document.sealed",
        "document.request_cancelled"
      ]
    }
    Response · 201
    {
      "data": {
        "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
        "name": "Contracts",
        "url": "https://contracts.example.com/passkey-x",
        "events": [
          "document.declined",
          "document.request_cancelled",
          "document.sealed",
          "document.signed"
        ],
        "enabled": true,
        "health": "waiting",
        "secret": "pxwh_<shown once>"
      }
    }

    Notable errors: conflict

    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/webhooks' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Idempotency-Key: contracts-hook-001' \
      -H 'Content-Type: application/json' \
      --data '{
      "name": "Contracts",
      "url": "https://contracts.example.com/passkey-x",
      "events": [
        "document.signed",
        "document.declined",
        "document.sealed",
        "document.request_cancelled"
      ]
    }'
  • GET/v1/webhooks/{webhook_id}One webhookNew in 1.6Scope: webhooks:read

    A webhook's events, health, cursor (delivered_through) and last attempt.

    ParameterInTypeDescription
    webhook_idrequiredpathuuidThe webhook.
    Response · 200
    {
      "data": {
        "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
        "name": "Contracts",
        "events": [
          "document.signed"
        ],
        "enabled": true,
        "delivered_through": 18342,
        "health": "delivering"
      }
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/webhooks/f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • PATCH/v1/webhooks/{webhook_id}Change a webhookNew in 1.6Scope: webhooks:write

    Renames it, pauses or resumes it (resuming clears the failure count) or replaces its events (an empty list means every event).

    ParameterInTypeDescription
    webhook_idrequiredpathuuidThe webhook.
    Request body
    {
      "enabled": true,
      "events": [
        "document.",
        "security_alert.raised"
      ]
    }
    Response · 200
    {
      "data": {
        "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
        "name": "Contracts",
        "events": [
          "document.",
          "security_alert.raised"
        ],
        "enabled": true,
        "health": "waiting"
      }
    }
    cURL
    curl -sS -X PATCH 'https://passkey-x.com/api/org/v1/webhooks/f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "enabled": true,
      "events": [
        "document.",
        "security_alert.raised"
      ]
    }'
  • DELETE/v1/webhooks/{webhook_id}Delete a webhookNew in 1.6Scope: webhooks:write

    Stops deliveries and deletes the webhook and its delivery log.

    ParameterInTypeDescription
    webhook_idrequiredpathuuidThe webhook.
    Response · 200
    {
      "data": {
        "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
        "deleted": true
      }
    }
    cURL
    curl -sS -X DELETE 'https://passkey-x.com/api/org/v1/webhooks/f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/webhooks/{webhook_id}/rotate-secretRotate the signing secretNew in 1.6Scope: webhooks:write

    Replaces the secret at once and returns the new one (shown once). Deploy it to your receiver right away.

    ParameterInTypeDescription
    webhook_idrequiredpathuuidThe webhook.
    Response · 200
    {
      "data": {
        "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
        "secret": "pxwh_<shown once>"
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/webhooks/f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b/rotate-secret' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/webhooks/{webhook_id}/testSend a testNew in 1.6Scope: webhooks:write

    Sends one signed audit_webhook.test event. The result appears in the delivery log within a few seconds. One test every 10 seconds.

    ParameterInTypeDescription
    webhook_idrequiredpathuuidThe webhook.
    Response · 202
    {
      "data": {
        "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
        "test_sent_at": "2026-10-26T09:30:00Z"
      }
    }

    Notable errors: conflict

    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/webhooks/f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b/test' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/webhooks/{webhook_id}/deliveriesDelivery logNew in 1.6Scope: webhooks:read

    Recent delivery attempts and tests, newest first (the latest 200 are kept).

    ParameterInTypeDescription
    webhook_idrequiredpathuuidThe webhook.
    limitqueryinteger1–200 (default 50).
    Response · 200
    {
      "data": [
        {
          "id": 981,
          "kind": "delivery",
          "ok": true,
          "status": 200,
          "error": null,
          "through_sequence": 18342,
          "created_at": "2026-10-26T09:30:00Z"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/webhooks/f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b/deliveries?limit=50' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/webhooks/{webhook_id}/replayReplay eventsNew in 1.6Scope: webhooks:write

    Sends events again starting at from_sequence (an audit event of the last 30 days), for example after your receiver lost data. Deliveries stay in order; deduplicate on sequence.

    ParameterInTypeDescription
    webhook_idrequiredpathuuidThe webhook.
    Request body
    {
      "from_sequence": 18001
    }
    Response · 200
    {
      "data": {
        "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
        "from_sequence": 18001,
        "delivered_through": 18000
      }
    }
    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/webhooks/f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b/replay' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Content-Type: application/json' \
      --data '{
      "from_sequence": 18001
    }'

Controller

  • GET/v1/controllerComputers, groups and recent actionsNew in 1.7Scope: controller:read

    Every active computer the Controller manages (platform, versions, online, score, baseline and drift, lost mode, Seal Chain state, update state), the groups with their update rings, and the latest 100 actions. Needs the Controller (Business and Enterprise).

    Response · 200
    {
      "data": {
        "computers": [
          {
            "id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
            "name": "FIN-LAPTOP-07",
            "platform": "windows",
            "group_id": "2d3e4f5a-6b7c-4d8e-9f0a-1b2c3d4e5f6a",
            "controller_version": "1.4.0",
            "app_version": "1.18.0",
            "service_mode": true,
            "last_checkin_at": "2026-10-26T09:30:00Z",
            "online": true,
            "score": 92,
            "baseline_version": 4,
            "baseline_mode": "enforce",
            "drift": 0,
            "lost": false,
            "chain_intact": true,
            "chain_length": 1288,
            "update_state": "current"
          }
        ],
        "groups": [
          {
            "id": "2d3e4f5a-6b7c-4d8e-9f0a-1b2c3d4e5f6a",
            "name": "Finance",
            "kind": "department",
            "mode": "enforce",
            "baseline_version": 4,
            "update_channel": "stable",
            "pinned_version": null,
            "rollout_percent": 100,
            "halted": false,
            "halted_reason": null
          }
        ],
        "jobs": [
          {
            "id": "3e4f5a6b-7c8d-4e9f-8a1b-2c3d4e5f6a7b",
            "kind": "scan",
            "status": "running",
            "target_kind": "group",
            "computers": 18,
            "group_id": "2d3e4f5a-6b7c-4d8e-9f0a-1b2c3d4e5f6a",
            "reason": "Weekly check",
            "source": "api",
            "created_at": "2026-10-26T09:30:00Z",
            "finished_at": null
          }
        ]
      }
    }

    Notable errors: plan_required

    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/controller' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/controller/jobsRun an action on computersNew in 1.7Scope: controller:write

    Queues an action for computers, a group or every computer, in the name of the key's owner (recorded as source "api"). Actions that need no signature: lock_screen, message, scan, diagnostics, sync_now, update_app, update_controller, found, app_lock, app_sign_out, app_sync, app_message, and on Controller Enterprise rotate_password and end_elevation. Restart, shutdown, settings, install, uninstall, elevate, wipe and lost mode must be signed by an administrator in the admin console and answer 403 signature_required. Actions expire after 72 hours if a computer never checks in.

    ParameterInTypeDescription
    Idempotency-Keyheaderstring8–128 characters; a repeat within 24 hours returns the first answer.
    Request body
    {
      "kind": "scan",
      "target_kind": "group",
      "group_id": "2d3e4f5a-6b7c-4d8e-9f0a-1b2c3d4e5f6a",
      "computer_ids": [],
      "payload": {},
      "reason": "Weekly check"
    }
    Response · 201
    {
      "data": {
        "id": "3e4f5a6b-7c8d-4e9f-8a1b-2c3d4e5f6a7b",
        "status": "queued"
      }
    }

    Notable errors: invalid_bodyinvalid_parametersignature_requiredplan_required

    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/controller/jobs' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Idempotency-Key: scan-finance-2026-10-26' \
      -H 'Content-Type: application/json' \
      --data '{
      "kind": "scan",
      "target_kind": "group",
      "group_id": "2d3e4f5a-6b7c-4d8e-9f0a-1b2c3d4e5f6a",
      "computer_ids": [],
      "payload": {},
      "reason": "Weekly check"
    }'
  • GET/v1/controller/jobs/{job_id}One action and its resultsNew in 1.7Scope: controller:read

    An action's status and payload with one run per computer: sent, done, failed or skipped, the computer's detail message and whether its Seal Chain entry verified.

    ParameterInTypeDescription
    job_idrequiredpathuuidThe action.
    Response · 200
    {
      "data": {
        "id": "3e4f5a6b-7c8d-4e9f-8a1b-2c3d4e5f6a7b",
        "kind": "scan",
        "status": "done",
        "payload": {},
        "reason": "Weekly check",
        "source": "api",
        "created_at": "2026-10-26T09:30:00Z",
        "expires_at": "2026-10-29T09:30:00Z",
        "finished_at": "2026-10-26T09:30:00Z",
        "runs": [
          {
            "computer_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
            "status": "done",
            "detail": "No issues found",
            "updated_at": "2026-10-26T09:30:00Z",
            "chain_ok": true
          }
        ]
      }
    }

    Notable errors: not_found

    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/controller/jobs/3e4f5a6b-7c8d-4e9f-8a1b-2c3d4e5f6a7b' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"

Remote

  • GET/v1/remoteSeats, devices and sessionsNew in 1.7Scope: remote:read

    Remote seats (bought and given), the devices enrolled for unattended or attended access (online when seen in the last 2 minutes) and the latest 200 sessions with who started them, the device, access (view or control), participants and how they ended. Screens, input and chat are end-to-end encrypted and never reach the API.

    Response · 200
    {
      "data": {
        "seats": {
          "total": 3,
          "assigned": 2
        },
        "devices": [
          {
            "id": "4f5a6b7c-8d9e-4f0a-9b2c-3d4e5f6a7b8c",
            "label": "Reception PC",
            "platform": "windows",
            "can_control": true,
            "unattended": true,
            "online": true,
            "last_seen_at": "2026-10-26T09:30:00Z"
          }
        ],
        "sessions": [
          {
            "id": "5a6b7c8d-9e0f-4a1b-8c3d-4e5f6a7b8c9d",
            "kind": "support",
            "title": "Printer setup",
            "status": "ended",
            "access": "control",
            "unattended": false,
            "started_by": "Ravi Kumar",
            "host": "Ana Ruiz",
            "device": null,
            "created_at": "2026-10-26T09:30:00Z",
            "started_at": "2026-10-26T09:30:00Z",
            "ended_at": "2026-10-26T09:30:00Z",
            "end_reason": "host",
            "participants": 2
          }
        ]
      }
    }

    Notable errors: addon_required

    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/remote' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/remote/sessions/{session_id}/endEnd a sessionNew in 1.7Scope: remote:write

    Ends a live session for everyone (screen sharing, control and any recording stop). Recorded as remote.session_ended with source api.

    ParameterInTypeDescription
    session_idrequiredpathuuidThe session.
    Response · 200
    {
      "data": true
    }

    Notable errors: not_found

    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/remote/sessions/5a6b7c8d-9e0f-4a1b-8c3d-4e5f6a7b8c9d/end' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • GET/v1/remote/invitesList invite linksNew in 1.7Scope: remote:read

    The latest 200 invite links for people outside the organization (open, used, revoked or expired) with the access they asked for and the session they joined.

    Response · 200
    {
      "data": [
        {
          "id": "6b7c8d9e-0f1a-4b2c-9d4e-5f6a7b8c9d0e",
          "email": "customer@example.com",
          "note": "Ticket 4411",
          "requested_access": "control",
          "status": "open",
          "expires_at": "2026-10-27T09:30:00Z",
          "session_id": null,
          "source": "api",
          "created_at": "2026-10-26T09:30:00Z"
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/org/v1/remote/invites' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"
  • POST/v1/remote/invitesCreate an invite linkNew in 1.7Scope: remote:write

    Creates a one-time link that lets someone outside the organization share their screen with the key's owner (who needs a Remote seat), for example from your helpdesk when a ticket is opened. Access is view or control (default control; the person still chooses on their device), valid 1–168 hours (default 24). The secret travels in the link's #fragment, which browsers never send to a server.

    ParameterInTypeDescription
    Idempotency-Keyheaderstring8–128 characters; a repeat within 24 hours returns the first answer.
    Request body
    {
      "email": "customer@example.com",
      "note": "Ticket 4411",
      "access": "control",
      "hours": 24
    }
    Response · 201
    {
      "data": {
        "invite_id": "6b7c8d9e-0f1a-4b2c-9d4e-5f6a7b8c9d0e",
        "url": "https://passkey-x.com/?view=remote#invite=<one-time secret>",
        "expires_at": "2026-10-27T09:30:00Z"
      }
    }

    Notable errors: invalid_parameterseat_required

    cURL
    curl -sS -X POST 'https://passkey-x.com/api/org/v1/remote/invites' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
      -H 'Idempotency-Key: ticket-4411-remote' \
      -H 'Content-Type: application/json' \
      --data '{
      "email": "customer@example.com",
      "note": "Ticket 4411",
      "access": "control",
      "hours": 24
    }'
  • DELETE/v1/remote/invites/{invite_id}Revoke an invite linkNew in 1.7Scope: remote:write

    The link stops working at once. Recorded as remote.invite_revoked.

    ParameterInTypeDescription
    invite_idrequiredpathuuidThe invite.
    Response · 200
    {
      "data": true
    }

    Notable errors: not_found

    cURL
    curl -sS -X DELETE 'https://passkey-x.com/api/org/v1/remote/invites/6b7c8d9e-0f1a-4b2c-9d4e-5f6a7b8c9d0e' \
      -H "Authorization: Bearer $PASSKEY_X_API_KEY"

API key scopes

Give each integration only what it needs. A key can hold up to 40 scopes, and an organization can have 20 active keys.

ScopeAllows
audit:readAudit events and item timelines
alerts:readSecurity alerts
alerts:writeAcknowledge and resolve alerts
members:readMembers and invitations
members:writeInvite, suspend, reactivate and offboard
reports:readSecurity summary, weekly reports, member security
workspaces:readShared vaults (no names)
groups:readDirectory groups
access:readVault access requests
access:writeApprove and deny vault access requests
onboarding:readOnboarding progress
onboarding:writeRemind, extend, resume and cancel onboarding
sharing:readExternal sharing requests
sharing:writeApprove and decline external links
handover:readHandovers and previews
handover:writeHand over a leaver's access
policies:readSecurity policies
storage:readStorage pool, usage and Runway
insights:readTrust Index and insights
documents:readDocument register, signature requests, proofs and verification
security:readSign-in risk, incidents and device trust
logs:readLogs: audit, sign-ins, API calls, emails and alerts
company:readCompany profile, address, access rules and devices
devices:writeIssue and cancel device codes, remove devices
policies:writeSet, enforce and stop policies
signatures:writeCancel signature requests
webhooks:readWebhooks, delivery log and the event catalog
webhooks:writeCreate, change, test, replay and delete webhooks
controller:readController computers, groups and actions
controller:writeRun unsigned Controller actions
remote:readRemote seats, devices, sessions and invite links
remote:writeEnd sessions, create and revoke invite links

Recipes

HR leaver: preview, hand over, offboard
# 1. What would move? (vaults they manage + passwords used in the last 90 days)
curl -s "https://passkey-x.com/api/org/v1/handovers/preview?from=$LEAVER_ID&to=$SUCCESSOR_ID" \
  -H "Authorization: Bearer $PASSKEY_X_API_KEY"

# 2. Hand over: the successor becomes manager and gets the passwords to rotate
curl -s -X POST 'https://passkey-x.com/api/org/v1/handovers' \
  -H "Authorization: Bearer $PASSKEY_X_API_KEY" -H 'Content-Type: application/json' \
  -d "{\"from_identity_id\":\"$LEAVER_ID\",\"to_identity_id\":\"$SUCCESSOR_ID\",\"note\":\"HR-4411\"}"

# 3. Offboard: access to every shared vault ends immediately
curl -s -X DELETE "https://passkey-x.com/api/org/v1/members/$LEAVER_ID" \
  -H "Authorization: Bearer $PASSKEY_X_API_KEY"
Contract system: follow signatures with a webhook
# 1. Subscribe to signatures only (the secret is shown once: store it)
curl -s -X POST 'https://passkey-x.com/api/org/v1/webhooks' \
  -H "Authorization: Bearer $PASSKEY_X_API_KEY" -H 'Content-Type: application/json' \
  -d '{"name":"Contracts","url":"https://contracts.example.com/passkey-x","events":["document.signed","document.declined","document.sealed","document.request_cancelled"]}'

# 2. Who still has to sign?
curl -s 'https://passkey-x.com/api/org/v1/signature-requests?status=pending' -H "Authorization: Bearer $PASSKEY_X_API_KEY"

# 3. Cancel a request that was superseded
curl -s -X POST "https://passkey-x.com/api/org/v1/documents/$DOCUMENT_ID/cancel" \
  -H "Authorization: Bearer $PASSKEY_X_API_KEY" -H 'Content-Type: application/json' -d '{"reason":"Replaced by v2"}'
Daily: nudge overdue onboarding
curl -s 'https://passkey-x.com/api/org/v1/onboarding?status=overdue' -H "Authorization: Bearer $PASSKEY_X_API_KEY" \
  | jq -r '.data[].id' \
  | xargs -I{} curl -s -X POST "https://passkey-x.com/api/org/v1/onboarding/{}/remind" -H "Authorization: Bearer $PASSKEY_X_API_KEY"
ITSM: approve an external share from a ticket
curl -s 'https://passkey-x.com/api/org/v1/external-shares?status=pending' -H "Authorization: Bearer $PASSKEY_X_API_KEY"

curl -s -X POST "https://passkey-x.com/api/org/v1/external-shares/$LINK_ID/approve" \
  -H "Authorization: Bearer $PASSKEY_X_API_KEY" -H 'Content-Type: application/json' \
  -d '{"note":"CHG-2207 approved by Security"}'
Helpdesk: send a Remote link when a ticket is opened
# The link lets the customer share their screen with the key's owner (who needs a Remote seat)
curl -s -X POST 'https://passkey-x.com/api/org/v1/remote/invites' \
  -H "Authorization: Bearer $PASSKEY_X_API_KEY" -H 'Content-Type: application/json' \
  -H "Idempotency-Key: ticket-$TICKET_ID" \
  -d "{\"email\":\"$CUSTOMER_EMAIL\",\"note\":\"Ticket $TICKET_ID\",\"access\":\"control\",\"hours\":24}"

# → { "data": { "invite_id": "…", "url": "https://passkey-x.com/?view=remote#invite=…", "expires_at": "…" } }
# Ticket closed early? Revoke the link:
curl -s -X DELETE "https://passkey-x.com/api/org/v1/remote/invites/$INVITE_ID" -H "Authorization: Bearer $PASSKEY_X_API_KEY"
RMM: scan a group of computers and follow the result
JOB=$(curl -s -X POST 'https://passkey-x.com/api/org/v1/controller/jobs' \
  -H "Authorization: Bearer $PASSKEY_X_API_KEY" -H 'Content-Type: application/json' \
  -d "{\"kind\":\"scan\",\"target_kind\":\"group\",\"group_id\":\"$GROUP_ID\",\"reason\":\"Weekly check\"}" | jq -r .data.id)

curl -s "https://passkey-x.com/api/org/v1/controller/jobs/$JOB" -H "Authorization: Bearer $PASSKEY_X_API_KEY" | jq '.data.runs'

Errors

Missing scope
{ "error": { "code": "forbidden", "message": "This key needs the alerts:write scope.", "request_id": "6f1c…" } }

400 invalid_parameter / invalid_body. 401 the key is missing, expired or revoked. 403 the key lacks the required scope, or plan_required. 404 the resource is not in your organization. 409 conflict: it was already decided, already exists or a limit was reached. 429 slow down and retry after Retry-After seconds. 503 try again shortly.

No-code tools: in Zapier use “Webhooks by Zapier” (or Make’s HTTP module) with the header Authorization: Bearer <key>, and poll /v1/alerts, /v1/external-shares?status=pending or /v1/audit-events?after=<last sequence>.

Agent API

For scripts, CI pipelines and automation agents that need secrets from vaults shared with them. The server only returns ciphertext; the passkey-x agent command decrypts it on the agent’s own machine.

Base URL
https://passkey-x.com/api/agent
Auth
Agent token (pxa1.<id>.<secret>)
Rate limit
One request per second per agent

Vaults

  • GET/v1/vaultsRead shared vaultsNeeds: Agent token

    Every vault shared with the agent: its sealed vault key and each item's current revision, all ciphertext. The passkey-x agent command decrypts it on the agent's own machine.

    Response · 200
    {
      "agent_id": "6b7c8d9e-0f1a-4b2c-9d3e-4f5a6b7c8d9e",
      "tenant_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
      "identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
      "name": "Deploy pipeline",
      "vaults": [
        {
          "workspace_id": "3f2a1b0c-9d8e-4f7a-8b6c-5d4e3f2a1b0c",
          "key_version": 1,
          "name": {
            "nonce": "\\xa1a1a1a1a1a1a1a1a1a1a1a1",
            "ciphertext": "\\x9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c"
          },
          "grant": {
            "ephemeral_public_key": "\\x04…",
            "nonce": "\\xa1a1a1a1a1a1a1a1a1a1a1a1",
            "ciphertext": "\\x9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c"
          },
          "items": [
            {
              "id": "c0ffee00-1234-4abc-8def-0123456789ab",
              "content_type": "api-key",
              "schema_version": 1,
              "revision": 3,
              "nonce": "\\xa1a1a1a1a1a1a1a1a1a1a1a1",
              "ciphertext": "\\x9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c",
              "aad_hash": "\\x5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d",
              "key_version": 1
            }
          ]
        }
      ]
    }
    cURL
    curl -sS -X GET 'https://passkey-x.com/api/agent/v1/vaults' \
      -H "Authorization: Bearer $PASSKEY_X_AGENT_TOKEN"

401 the token is invalid or was replaced. 403 agent_inactive: the agent was stopped, or the organization’s plan or kill switch doesn’t allow agents. Every read is written to the organization’s audit log.

Webhooks

Send audit events to your own endpoint in Admin console → Integrations → Audit streaming (choose “HTTPS webhook”). Subscribe to exact events from the event catalog (GET /v1/webhooks/events), for example document.signed or security_alert.raised, or to a prefix such as member., onboarding. or access_request.: a filter that names a catalog event matches that event only, anything else matches every event that starts with it. Webhooks can also be created and changed through the Organization API (scopes webhooks:read and webhooks:write). Each delivery is a JSON object (type: "audit_events", first_sequence, last_sequence, events: [...]) of up to 200 events, signed with your secret:

Delivery headers
POST /your/endpoint HTTP/1.1
Content-Type: application/json
User-Agent: Passkey-X-Webhooks/1
X-PasskeyX-Webhook: <webhook id>
X-PasskeyX-Timestamp: 1767225600
X-PasskeyX-Signature: v1=<hex HMAC-SHA256 of "<timestamp>.<raw body>" with your full pxwh_ secret>
Delivery body
{
  "source": "passkey-x",
  "type": "audit_events",
  "webhook_id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
  "tenant_id": "8b6a3f1e-2c4d-4e5f-9a0b-1c2d3e4f5a6b",
  "sent_at": "2026-10-26T09:30:02Z",
  "first_sequence": 18341,
  "last_sequence": 18342,
  "events": [
    { "sequence": 18342, "occurred_at": "2026-10-26T09:30:00Z", "action": "remote.session_ended",
      "target_type": "remote_sessions", "target_id": "5a6b7c8d-9e0f-4a1b-8c3d-4e5f6a7b8c9d",
      "actor_identity_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9", "metadata": { "seconds": 412, "people": 2 },
      "hash_version": 2, "event_hash": "9a7f…" }
  ]
}
Verify a delivery (Node.js)
import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(rawBody, timestamp, signature, secret) {
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  const expected = "v1=" + createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
  return expected.length === signature.length && timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

Verify the signature with a constant-time comparison and reject timestamps older than five minutes. Deliveries are at-least-once and in order (deduplicate on sequence). After a failure the next attempt waits 2, 4, 8, 16 and 32 minutes, then every 60 minutes, and nothing is skipped; a destination that fails 100 times in a row is paused. Recent attempts are listed under each destination (GET /v1/webhooks/{id}/deliveries), and POST /v1/webhooks/{id}/replay sends events of the last 30 days again from a sequence you choose. Splunk HEC, Datadog, Microsoft Sentinel and Elastic are built in.

Test events use "type": "test". Splunk, Datadog, Sentinel, Elastic, Slack and Teams destinations get the event in their own format and authenticate with the destination’s own credential instead of this signature.

Webhook events

The 96 events below can be subscribed to exactly (the same list as GET /v1/webhooks/events). A filter that is not in this list, such as member. or controller., matches every event that starts with it, including audit actions not listed here.

Documents and signing15 events
EventWhen
document.signature_requestedA signature request was sent
document.signedA signer signed a document (with the proof summary)
document.declinedA signer declined to sign
document.sealedEveryone signed: the document is sealed
document.request_cancelledA signature request was cancelled (by the sender, or the document was deleted)
document.revokedA sealed document was revoked
document.expiredA document or signature request expired
document.expiringA document expires soon
document.recordedA document signed elsewhere was recorded
document.signed_externalA document was signed with another provider
document.fields_changedThe fields of a pending request changed
document.request_emailedA signing link was emailed to an outside signer
document.signed_copy_storedThe signed copy was stored in the vault
document.signed_copy_emailedThe signed copy was emailed to the signers
document.signed_copy_resentThe signed copy was sent again
Members and directory12 events
EventWhen
member.invitedA person was invited to the organization
member.invitation_cancelledAn invitation was cancelled
member.blockedA member was blocked
member.unblockedA member was unblocked
tenant_memberships.role_changedA member's role changed
tenant_membership.removedA member was removed
onboarding.step_doneAn onboarding step was completed
onboarding.overdueAn onboarding plan is overdue
offboarding.startedOffboarding started
offboarding.completedOffboarding finished
scim.user_provisionedThe directory (SCIM) added a person
scim.user_deactivatedThe directory (SCIM) deactivated a person
Access and sharing10 events
EventWhen
access_request.createdSomeone asked for access to a vault
access_request.approvedAn access request was approved
access_request.deniedAn access request was denied
access.handoverAccess was handed over from one person to another
workspace.access_removedSomeone's access to a vault was removed
secure_send.createdA Secure Send link was created
secure_send.openedA Secure Send link was opened
secure_send.revokedA Secure Send link was revoked
emergency_access.requestedEmergency access was requested
emergency_access.activatedEmergency access was granted
Security11 events
EventWhen
security_alert.raisedA security alert was raised
security_incident.openedA security incident was opened
security_incident.updatedA security incident changed
session.revoked_by_adminAn administrator signed someone out
session.revoked_high_riskA risky sign-in was signed out
vault.unlock_failedA vault unlock failed
travel_mode.enabledTravel mode was turned on
travel_mode.disabledTravel mode was turned off
behavior_guard.hold_placedBehavior Guard paused an account
sso.configuredSingle sign-on was configured
policy.updatedA security policy changed
Vaults4 events
EventWhen
workspace.createdA vault was created
workspace.deletedA vault was deleted
vault_item.purgedA vault item was deleted for good
attachment.deletedA file was deleted
Company devices2 events
EventWhen
company_device.enrolledA company device was enrolled
company_device.removedA company device was removed
API keys and webhooks7 events
EventWhen
api_key.createdAn API key was created
api_key.revokedAn API key was revoked
audit_webhook.createdA webhook was created
audit_webhook.updatedA webhook's name or events changed
audit_webhook.deletedA webhook was deleted
audit_webhook.secret_rotatedA webhook's signing secret was replaced
audit_webhook.replayedA webhook was set to send earlier events again
Controller14 events
EventWhen
controller.job_createdA Controller action was created
controller.job_approvedA second administrator approved a Controller action
controller.job_deniedA Controller action was denied
controller.job_finishedEvery computer finished a Controller action
controller.job_failedA computer could not carry out a Controller action
controller.updates_haltedApp updates stopped for a group (by an admin or because updates failed)
controller.updates_resumedApp updates resumed for a group
controller.group_changedA Controller group or its signed baseline changed
controller.keys_changedThe Controller signing or escrow key changed
controller.password_rotatedA computer changed its local admin password
controller.password_checkout_requestedSomeone asked to see a local admin password
controller.password_revealedA local admin password was opened
controller.elevation_requestedA member asked for admin rights on a computer
micro_agent.enrolledA computer joined the Controller
Remote21 events
EventWhen
remote.session_startedA remote support session or screen share started (code, connect or share)
remote.session_acceptedThe person on the device allowed viewing or control (or unattended access was used)
remote.session_declinedThe person on the device declined
remote.session_endedA remote session ended (with its length and number of people)
remote.control_givenSomeone was given control of a shared screen
remote.participant_joinedSomeone joined a remote session or asked to
remote.unattended_onA device turned on unattended access
remote.invite_createdA remote support invite link was made (in the app or with the API)
remote.settings_changedRemote settings changed (unattended access, relay, outside people)
remote.control_takenThe person on the device took control back
remote.access_changedA participant's access changed between view and control
remote.participant_removedSomeone was removed from a remote session
remote.invite_revokedA remote support invite link was revoked (in the app or with the API)
remote.seat_givenA Remote seat was given to a member
remote.seat_removedA Remote seat was taken back
remote.recording_requestedA technician asked to record a session
remote.recording_allowedThe person on the device allowed recording
remote.recording_declinedThe person on the device declined recording
remote.recording_startedRecording started (saved encrypted to the organization's recordings vault)
remote.recording_stoppedRecording stopped
remote.transcript_savedA session's chat transcript was saved encrypted to the vault

SCIM 2.0 provisioning

Add, update and deactivate members and groups from Okta, Microsoft Entra ID, JumpCloud or any SCIM 2.0 identity provider. Turn it on in Admin console → Identity & SSO, copy the base URL and the token (pxscim_…, shown once), then map each group to a vault so membership follows your directory (guide).

Base URL
https://rqblosdixajthfdzqotj.supabase.co/functions/v1/scim/v2
Auth
Authorization: Bearer pxscim_…
Paging
startIndex, count (up to 200)
Method and pathWhat it does
GET /ServiceProviderConfigWhat this server supports (PATCH, filters, up to 200 results).
GET /ResourceTypes · GET /SchemasThe User and Group resource types and their schemas.
GET /Users · POST /UsersFind people (with a filter) or add one. A new person gets an invitation to the organization.
GET · PUT · PATCH · DELETE /Users/{id}Read, replace, change (active: false deactivates) or remove a person.
GET /Groups · POST /GroupsFind groups or add one.
GET · PUT · PATCH · DELETE /Groups/{id}Read, replace, add or remove members, or delete a group.

Filters: userName, externalId or emails eq for users; displayName or externalId eq for groups. PATCH follows RFC 7644 (add, replace and remove, including members[value eq "…"]). Errors use the SCIM error schema with scimType. Deactivating a user ends their access to every shared vault at once; their personal vault stays theirs.

Need help building on Passkey-X?

Questions about the API, a bug or a missing endpoint? Our team replies by email, usually within one business day.