Uncertain SystemsUncertain Systems
UpgradeDashboard

Uncertain Systems Proof-of-Work API

Workspace API Reference

Full request and response specifications for every Proof-of-Work API endpoint: workspaces, proof-of-work schema generation, integration skill generation, proof-of-work upload, performance analysis, TAP links, ILE practice, guest provisioning, and dashboard key management. Bearer endpoints use base path /api/v3/pow and require active api_metered.

Agent skill file →Get API key

Authentication

Authorization: Bearer <api_key>
Content-Type: application/json

Key types

FieldTypeRequiredDescription
sk_string prefix—Organization member key from dashboard or POST /api/v3/pow/keys (browser session).
gsk_string prefix—Guest key from POST /api/v3/pow/org/guests.

Error response

{
  "error": {
    "code": "forbidden",
    "message": "Human-readable explanation",
    "details": {}
  }
}

Common codes: unauthorized, key_revoked, key_expired, forbidden, api_plan_required, validation_error, workspace_not_found, block_not_found, tap_link_not_found, guest_not_found, not_found, rate_limit_exceeded (429).

Evaluation modes

Workspaces use evaluation_mode to choose between full semantic verification and privacy-preserving opaque protocol verification.

Modes

FieldTypeRequiredDescription
semanticdefault—Create with initial_prompt. Schema uses definition. Performance returns semantic gap_analysis.
opaqueprivacy mode—Create with protocol (protocol_id, goal_ref). Schema uses definition_ref + contract.event_verbs. Performance returns protocol_report; partner refs are stored but not semantically inferred.

Canonical opaque protocol agent-trace-v3: enumerate → fingerprint → aggregate → emit → validate. Upload metadata is allowlisted; tool payloads are plaintext-linted in opaque mode.

Scopes

Each Bearer-authenticated endpoint requires one scope. The wildcard * grants all scopes.

Scope reference

FieldTypeRequiredDescription
workspaces:readscope—List blocks; generate proof-of-work schemas and integration skills; call lwm-snapshot (LWM Snapshot).
workspaces:writescope—Upload proof of work (workspace create is UI-only).
tap:readscope—List TAP links and poll completion status (score via POST .../lwm-snapshot).
tap:writescope—Create Think Aloud Protocol (TAP) links for blocks.
org:readscope—Reserved for org admin keys (future org read endpoints).
org:writescope—Create guest users and issue gsk_ keys.
*scope—All scopes. Org admins only when assigning to sk_ keys.

Default sk_ key scopes: workspaces:read, workspaces:write, tap:read, tap:write. Guest gsk_ keys receive the same four scopes automatically.

Rate limits

API keys default to 120 requests per minute per key. Exceeding the limit returns 429 with code rate_limit_exceeded.

Endpoint index

  • POST /api/v3/pow/workspaces
  • POST /api/v3/snapshot/workspaces/{workspace_id}/lwm-snapshot
  • POST /api/v3/pow/workspaces/{workspace_id}/tap-links
  • GET /api/v3/pow/workspaces/{workspace_id}/tap-links
  • POST /api/v3/pow/org/guests
  • GET /api/v3/pow/keys
  • POST /api/v3/pow/keys
  • DELETE /api/v3/pow/keys/{key_id}
  • PATCH /api/v3/pow/keys/{key_id}/scopes
POST/api/v3/pow/workspacesworkspaces:write403 Forbidden

Not available. Programmatic workspace creation is disabled; create workspaces manually in the product UI at /workspace/new.

Response body

FieldTypeRequiredDescription
error.codestring—forbidden
error.messagestring—Workspace creation is not available via API or MCP. Create workspaces manually in the product UI at /workspace/new.

Response example

{
  "error": {
    "code": "forbidden",
    "message": "Workspace creation is not available via API or MCP. Create workspaces manually in the product UI at /workspace/new."
  }
}
  • Workspace creation is UI-only (blank, template, or files+goal at /workspace/new).
  • MCP tool create_workspace is not offered and hard-fails with the same message if called.
  • Use list_workspaces / get_workspace / get_learning_progress against UI-created workspace IDs.
POST/api/v3/snapshot/workspaces/{workspace_id}/lwm-snapshotworkspaces:read200 OK

LWM Snapshot score (0–100) + GHC + spider markers, analysis, and next actions. Sole product snapshot strategy. Manual Knowledge UI or Snapshot API/MCP (not auto on TAP/ILE end).

Path parameters

FieldTypeRequiredDescription
workspace_iduuidyesWorkspace ID.

Request body (JSON)

FieldTypeRequiredDescription
block_iduuid—Optional: scope analysis to one block.
style_promptstring—Optional voice/tone for narrative fields.
file_idsstring[]—Optional xAI file IDs from a prior score call. Empty → rebuild context bundle.

Request example

{ "block_id": "e57844a6-1b69-465c-9120-d0812d6339ae" }

Response body

FieldTypeRequiredDescription
mode"score"—Always score for this endpoint.
strategystring—lwm_snapshot
labelstring—LWM Snapshot
workspace_goalstring—Inferred or owner-set workspace goal.
reportobject—LWM Snapshot score report payload.
report.scoreinteger—0–100 primary LWM Snapshot score.
report.lwm_snapshot_scoreinteger—Named primary field (equals score).
report.ghc_scoreinteger—0–100 secondary GHC signal.
proof_of_work_summaryobject | null—Counts used in context.
file_idsstring[]—xAI file IDs for follow-up calls.

Response example

{
  "mode": "score",
  "strategy": "lwm_snapshot",
  "label": "LWM Snapshot",
  "workspace_goal": "Trial-to-paid subscription activation",
  "report": {
    "score": 68,
    "lwm_snapshot_score": 68,
    "ghc_score": 40,
    "workspace_goal": "Trial-to-paid subscription activation",
    "marker_scores": [],
    "summary": "...",
    "confidence": "developing"
  },
  "proof_of_work_summary": {
    "blocks": 1,
    "proof_of_work_artifacts": 2,
    "linked_sessions": 0,
    "workspace_files": 0
  },
  "file_ids": ["file_814439bd-4894-4e11-852d-314e9f777a7f"]
}
  • Sole product score strategy — no verification/augmentation/optimization score routes.
  • First call with empty file_ids uploads a workspace performance JSON summary + up to 19 artifact files to xAI.
  • If no proof of work exists, returns 200 with an empty-data score template.
POST/api/v3/pow/workspaces/{workspace_id}/tap-linkstap:write201 Created

Create a private Think Aloud Protocol (TAP) link for the workspace (or a block via body/path).

Path parameters

FieldTypeRequiredDescription
workspace_iduuidyesWorkspace ID.

Request body (JSON)

FieldTypeRequiredDescription
block_iduuid—Optional. When set, scopes the TAP session to that block. Omit for full-workspace scope.
minutesinteger—1–120; default 15.
guest_user_iduuid—Org admin only: assign link to a guest by ID.
guest_emailstring—Org admin only: assign link to a guest by email.
participant_typestring—anonymous | guest | user.
user_iduuid—Member user id when participant_type=user.
post_sessionstring—redirect_workspace | show_results | redirect_url.
redirect_urlstring—Required when post_session=redirect_url.

Request example

{
  "minutes": 15,
  "participant_type": "anonymous"
}

Response body

FieldTypeRequiredDescription
tap_link.iduuid—TAP link / session row ID.
tap_link.workspace_iduuid—Workspace ID.
tap_link.block_iduuid | null—Block ID when scoped; null for full workspace.
tap_link.statusstring—pending | in_progress | completed
tap_link.requested_duration_secondsinteger—Requested duration in seconds.
tap_link.focus_block_idsuuid[]—Focused block IDs (empty = full workspace).
tap_link.created_atISO-8601—Link creation time.
tap_link.private_urlstring—Bearer URL: /tap/session/{token}. No login required.
interruptionobject | null—TIM predictive interruption (see Predictive interruptions).

Response example

{
  "tap_link": {
    "id": "ae0cc774-1832-4bb5-bc7d-bf119ddf759f",
    "workspace_id": "75b3b4ef-4e47-4f39-bb09-f61406603d75",
    "block_id": null,
    "status": "pending",
    "requested_duration_seconds": 900,
    "focus_block_ids": [],
    "created_at": "2026-06-23T01:29:03.861663+00:00",
    "private_url": "https://uncertain.systems/tap/session/E8-ouJ9lErgDEmteyKc4tJ39meJ91vzZFNUiuRauHvw"
  }
}
  • Also available as POST .../blocks/{block_id}/tap-links for block-scoped links (same body fields).
  • Guest keys auto-attach the link to their guest identity.
  • Org admins may set guest_user_id or guest_email to assign the link (404 guest_not_found if missing).
  • Learner completes session at private_url without an API key.
GET/api/v3/pow/workspaces/{workspace_id}/tap-linkstap:read200 OK

List TAP links for a workspace (filtered by caller role).

Path parameters

FieldTypeRequiredDescription
workspace_iduuidyesWorkspace ID.

Response body

FieldTypeRequiredDescription
tap_linksarray—Sessions ordered by created_at descending.
tap_links[].iduuid—Link ID.
tap_links[].workspace_iduuid—Workspace ID.
tap_links[].block_iduuid | null—Block ID when scoped; null for full workspace.
tap_links[].statusstring—pending | in_progress | completed
tap_links[].requested_duration_secondsinteger—Requested duration.
tap_links[].duration_secondsinteger—Actual duration (0 until completed).
tap_links[].focus_block_idsuuid[]—Focused blocks.
tap_links[].scoreinteger | null—Score when completed.
tap_links[].created_atISO-8601—Created at.
tap_links[].started_atISO-8601 | null—Started at.
tap_links[].completed_atISO-8601 | null—Completed at.
interruptionobject | null—TIM predictive interruption.

Response example

{
  "tap_links": [
    {
      "id": "ae0cc774-1832-4bb5-bc7d-bf119ddf759f",
      "workspace_id": "75b3b4ef-4e47-4f39-bb09-f61406603d75",
      "block_id": "88a43ad8-62f8-4252-a847-2cbc0b754a57",
      "status": "completed",
      "requested_duration_seconds": 900,
      "duration_seconds": 120,
      "focus_block_ids": ["88a43ad8-62f8-4252-a847-2cbc0b754a57"],
      "lwm_snapshot_score": 72,
      "created_at": "2026-06-23T01:29:03.861663+00:00",
      "started_at": "2026-06-23T01:30:00+00:00",
      "completed_at": "2026-06-23T01:32:21.492+00:00"
    }
  ]
}
  • Guests see only their own links.
  • Non-admin members see only links they created.
  • Org admins see all links on org workspaces.
POST/api/v3/pow/org/guestsorg:write201 Created (new guest) or 200 OK (existing guest)

Create or look up a guest by email and issue a new guest API key (gsk_).

Request body (JSON)

FieldTypeRequiredDescription
emailstringyesGuest email address (normalized to lowercase).

Request example

{ "email": "learner@example.com" }

Response body

FieldTypeRequiredDescription
guest_user.iduuid—organization_guest_users.id
guest_user.organization_iduuid—Org the guest belongs to.
guest_user.emailstring—Guest email.
guest_user.statusstring—active | claimed | revoked
guest_user.claimed_by_user_iduuid | null—Set when guest signs up with same email.
guest_user.claimed_atISO-8601 | null—Claim timestamp.
guest_user.created_atISO-8601—Guest record created at.
api_keystring—Raw gsk_ key — shown once; store securely.
key.iduuid—agent_api_keys.id
key.key_prefixstring—First 13 chars of key for identification.
key.scopesstring[]—workspaces:read, workspaces:write, tap:read, tap:write
key.rate_limitinteger—Requests per minute (default 120).
key.created_atISO-8601—Key creation time.

Response example

{
  "guest_user": {
    "id": "f8b2c1d0-1234-5678-9abc-def012345678",
    "organization_id": "64cc093b-31c1-4a7e-aead-e2e9378ecaf4",
    "email": "learner@example.com",
    "status": "active",
    "claimed_by_user_id": null,
    "claimed_at": null,
    "created_at": "2026-06-23T13:00:00+00:00"
  },
  "api_key": "gsk_a1b2c3d4e5f6789012345678abcdef",
  "key": {
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "key_prefix": "gsk_a1b2c3d4",
    "scopes": ["workspaces:read", "workspaces:write", "tap:read", "tap:write"],
    "rate_limit": 120,
    "created_at": "2026-06-23T13:00:01+00:00"
  }
}
  • Caller must be organization admin with org:write on their sk_ key.
  • Re-calling for the same email mints another key; prior keys may remain active.
  • 409 if email belongs to a real user in another organization.
GET/api/v3/pow/keysbrowser session200 OK

List API keys for the signed-in dashboard user. Uses Supabase session cookies — not Bearer API key auth.

Response body

FieldTypeRequiredDescription
keysarray—All agent_api_keys for the authenticated user, newest first.
keys[].iduuid—Key ID.
keys[].labelstring | null—Optional label set at creation.
keys[].key_prefixstring—First 12 characters of sk_ key (identification only).
keys[].scopesstring[]—Assigned scopes.
keys[].rate_limitinteger—Requests per minute (default 120).
keys[].is_activeboolean—False after revocation.
keys[].created_atISO-8601—Creation timestamp.
keys[].last_used_atISO-8601 | null—Last successful API call.
keys[].expires_atISO-8601 | null—Expiry if set at creation.

Response example

{
  "keys": [
    {
      "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
      "label": "Production agent",
      "key_prefix": "sk_a1b2c3d4e5",
      "scopes": ["workspaces:read", "workspaces:write", "tap:read", "tap:write"],
      "rate_limit": 120,
      "is_active": true,
      "created_at": "2026-06-23T12:00:00+00:00",
      "last_used_at": "2026-06-23T13:05:00+00:00",
      "expires_at": null
    }
  ]
}
  • Also available from Dashboard → Usage & API. Max 10 active keys per user.
POST/api/v3/pow/keysbrowser session201 Created

Create a new sk_ API key for the signed-in user. Raw key returned once.

Request body (JSON)

FieldTypeRequiredDescription
labelstring—Optional label, max 128 characters.
scopesstring[]—Optional. Default: workspaces:read, workspaces:write, tap:read, tap:write. org:read/org:write require org admin.
expires_in_daysinteger—Optional expiry: 1–365 days.

Request example

{
  "label": "CI pipeline",
  "scopes": ["workspaces:read", "workspaces:write", "tap:read", "tap:write", "org:write"],
  "expires_in_days": 90
}

Response body

FieldTypeRequiredDescription
key.iduuid—agent_api_keys.id
key.labelstring | null—Label if provided.
key.key_prefixstring—First 12 chars of sk_ key.
key.scopesstring[]—Assigned scopes.
key.rate_limitinteger—Default 120.
key.created_atISO-8601—Creation time.
key.expires_atISO-8601 | null—Expiry if set.
api_keystring—Full sk_ key — shown once; store securely.

Response example

{
  "key": {
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "label": "CI pipeline",
    "key_prefix": "sk_a1b2c3d4e5",
    "scopes": ["workspaces:read", "workspaces:write", "tap:read", "tap:write", "org:write"],
    "rate_limit": 120,
    "created_at": "2026-06-23T12:00:00+00:00",
    "expires_at": "2026-09-21T12:00:00+00:00"
  },
  "api_key": "sk_7f3a9b2c1d4e5f6789012345678abcdef"
}
  • Requires Teams tier (403 api_plan_required).
  • Valid scopes: *, workspaces:read, workspaces:write, tap:read, tap:write, org:read, org:write.
  • 403 if more than 10 active keys or if non-admin requests org scopes.
DELETE/api/v3/pow/keys/{key_id}browser session200 OK

Revoke (soft-delete) an API key owned by the signed-in user.

Path parameters

FieldTypeRequiredDescription
key_iduuidyesagent_api_keys.id from list or create.

Response body

FieldTypeRequiredDescription
deletedboolean—True on success.
key_iduuid—Revoked key ID.

Response example

{
  "deleted": true,
  "key_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab"
}
  • 404 not_found if key does not belong to user. 400 if already revoked.
PATCH/api/v3/pow/keys/{key_id}/scopesbrowser session200 OK

Replace scopes on an active API key.

Path parameters

FieldTypeRequiredDescription
key_iduuidyesagent_api_keys.id.

Request body (JSON)

FieldTypeRequiredDescription
scopesstring[]yesNon-empty array of valid scope strings.

Request example

{
  "scopes": ["workspaces:read", "tap:read"]
}

Response body

FieldTypeRequiredDescription
key.iduuid—Updated key ID.
key.scopesstring[]—New scope list.
key.updated_atISO-8601—Update timestamp.

Response example

{
  "key": {
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "scopes": ["workspaces:read", "tap:read"],
    "updated_at": "2026-06-23T13:10:00+00:00"
  }
}
  • Cannot update revoked keys. org:read/org:write require organization admin.

TAP session completion (learner-facing)

Learners open private_url without an API key. Completion uses web APIs (not Proof-of-Work API):

POST /api/workspace-tap-score/chat

FieldTypeRequiredDescription
privateTokenstringyesToken from private_url path.
thoughtstringyesLearner thought fragment.
messagesarray—Optional prior chat messages.

POST /api/workspace-tap-score/complete

FieldTypeRequiredDescription
privateTokenstringyesToken from private_url path.
transcriptarrayyesSession transcript entries with role and text.
durationSecondsinteger—Elapsed session seconds.

For agents

Machine-readable spec

Agents should also load /skill.md for integration checklists, guest responsibilities, and MCP transport. Generate a custom skill per workspace via POST .../integration-skill, or add the PumaDoc policy snippets: Customer Agent policy, PumaClaw Mentor policy.

Uncertain SystemsUncertain Systems

A knowledge workspace with software tools that verify and augment learning for humans and AI agents.

Product

  • Vision
  • Science
  • Pricing
  • Proof-of-Work API

Workspace

  • Create workspace
  • Agent skill file

Resources

  • GitHub

Legal

  • Privacy
  • Terms
  • Cookies
  • Legal Notice
@uncertainsysdaniel@uncertain.systems

© 2026 Uncertain Systems (Daniel Colomer). All rights reserved.

Building the open stack for educational technology