WorkCapacity
Power Oracle Docs

API Reference

Public endpoints, request shape, response structure, and live schema access for Power Oracle.

Live Endpoints

Agents and software systems should use the OpenAPI schema directly.

Browsable Swagger and ReDoc interfaces are local-development tooling and are not part of the deployed public contract.

The current public contract is versioned under /v1. External users should integrate against the /v1/* routes.

Current Public Endpoints

  • GET /v1/health
  • GET /v1/movements
  • GET /v1/payment-requirements
  • GET /v1/athletes/{athlete_uuid}/workouts
  • GET /v1/athletes/{athlete_uuid}/workouts/{workout_id}
  • GET /v1/athletes/{athlete_uuid}/curve
  • POST /v1/compute-power
  • POST /v1/workouts/\{workout_id\}/revisions
  • POST /v1/workouts/\{workout_id\}/void

GET /v1/health

Use this as a liveness check.

Example:

curl https://api.workcapacity.io/v1/health

GET /v1/movements

This endpoint returns the public movement registry that clients should consult before building compute requests.

Use it to discover:

  • supported movement names
  • required inputs
  • alternative input rules
  • supported overrides
  • public modeling assumptions

Why it matters:

  • It tells you which movements the system supports right now.
  • It tells you which inputs are required versus optional.
  • It helps an agent refuse to guess when a movement or required input is missing.
  • It keeps clients aligned with the current movement library instead of hard-coding stale assumptions.

Sample Response Fragment

{
  "air_squat": {
    "name": "air_squat",
    "required_inputs": [],
    "supported_overrides": ["height_coefficient"]
  },
  "thruster": {
    "name": "thruster",
    "required_inputs": [
      {
        "name": "external_load",
        "required": true,
        "allowed_units": ["kg", "lb"]
      }
    ],
    "supported_overrides": ["height_coefficient", "load_height_coefficient"]
  },
  "row": {
    "name": "row",
    "required_inputs": [],
    "alternative_inputs": [
      {
        "description": "Provide either rowing distance or displayed calories.",
        "options": [
          { "name": "travel_distance", "allowed_units": ["m", "ft"] },
          { "name": "calories", "allowed_units": ["kcal"] }
        ]
      }
    ]
  }
}

Required vs Optional Inputs

  • air_squat needs no movement-specific input.
  • thruster requires inputs.external_load.
  • row requires exactly one alternative input: travel_distance or calories.
  • Overrides are optional and should only be sent when the client explicitly intends to depart from the default assumption.

GET /v1/payment-requirements

This endpoint returns the current public payment metadata for paid routes.

Use it to discover:

  • which routes are currently paid
  • the public display price for each route
  • the currently resolved L402 sat amount when a BTC/USD quote is available
  • the route policy identifier
  • any public Bazaar metadata that describes the paid route

Sample Response Fragment

{
  "routes": [
    {
      "method": "POST",
      "path": "/v1/compute-power",
      "policy_id": "compute-power-v2",
      "protocol": "l402",
      "payment_mode": "single_use",
      "price": "$0.10",
      "price_sats": 100
    },
    {
      "method": "POST",
      "path": "/v1/compute-power",
      "policy_id": "compute-power-v2",
      "protocol": "x402",
      "payment_mode": "single_use",
      "price": "$0.10"
    },
    {
      "method": "POST",
      "path": "/v1/workouts/{workout_id}/revisions",
      "policy_id": "workout-revision-v1",
      "protocol": "l402",
      "payment_mode": "single_use",
      "price": "$0.04",
      "price_sats": 40
    },
    {
      "method": "POST",
      "path": "/v1/workouts/{workout_id}/revisions",
      "policy_id": "workout-revision-v1",
      "protocol": "x402",
      "payment_mode": "single_use",
      "price": "$0.04"
    }
  ]
}

GET /v1/athletes/{athlete_uuid}/workouts

Returns an athlete's active canonical completed workouts, newest first. The athlete_uuid is a capability token. No bearer token or payment challenge is required.

Query parameters:

  • limit: page size, 1-100, default 20
  • cursor: opaque next-page cursor from the previous response
  • since: only workouts on or after this performed date
  • until: only workouts on or before this performed date
  • domain: short, medium, or long
  • movement: exact movement name from GET /v1/movements
  • updated_since: only workouts updated at or after this UTC timestamp

The response includes total, has_more, cursor, and items[]. total is the count of active canonical workouts matching the supplied filters.

Each item includes workout_id, revision_id, revision_number, performed_date, updated_at, duration, total work, active average power, split count, rest flag, movement names, and notes.

GET /v1/athletes/{athlete_uuid}/workouts/{workout_id}

Returns one active canonical workout detail record for the given athlete. This is the route agents should use before deciding whether a past workout needs a correction or void.

The response includes:

  • workout metadata with canonical workout_id, revision_id, and revision_number
  • performed_date and updated_at
  • results.session
  • results.splits[]
  • results.summary
  • results.movement_rollups[]
  • notes

The route returns 404 when the athlete is unknown, the workout is unknown, the workout belongs to a different athlete, or the workout has been voided.

GET /v1/athletes/{athlete_uuid}/curve

Returns a bounded power-duration curve for active canonical completed workouts. This route is public and uuid-gated.

Query parameters:

  • since: only workouts on or after this performed date
  • until: only workouts on or before this performed date
  • max_points: maximum newest matching workout points to process and return, default 500, maximum 1000
  • include_points: all or envelope
  • trend_window_days: recent trend window, default 14, maximum 60
  • trend_baseline_days: baseline window before the recent window, default 90, range 7-365

The response includes:

  • points: returned workout points sorted by duration ascending
  • envelope_points: Pareto-optimal points sorted by duration ascending
  • work_capacity_auc: area under the returned envelope in joules, using trapezoidal integration over linear duration
  • domain_slices: short, medium, and long bests
  • domain_trends: recent-versus-baseline trends computed within each duration domain

work_capacity_auc is a Power Oracle work-capacity estimate over the selected response window. It is aligned with CrossFit's work-capacity curve framing, but it is only as complete as the athlete's logged coverage across time and modal domains.

POST /v1/compute-power

POST /v1/compute-power accepts a session-first, split-aware request body.

Required Top-Level Fields

  • athlete_uuid
  • evaluation_context
  • duration_seconds
  • user
  • splits

Context Rules

  • completed requires performed_date
  • planned requires planned_for_date
  • planned and hypothetical may include scenario_label
  • hypothetical must not include performed_date or planned_for_date

User Object

  • height
  • body_mass
  • optional age_years
  • optional sex
  • optional response_units

Each Split Includes

  • optional label
  • active duration_seconds
  • optional rest_seconds_after
  • work.movements[]

Time Rules

  • Top-level duration_seconds is session elapsed time.
  • Split duration_seconds is split active time.
  • rest_seconds_after is recovery after that split.
  • If session elapsed time exceeds accounted split time, the response returns unattributed_duration_seconds.

Example Request

{
  "athlete_uuid": "11111111-1111-1111-1111-111111111111",
  "evaluation_context": "completed",
  "performed_date": "2026-03-20",
  "duration_seconds": 133,
  "user": {
    "height": { "value": 70, "unit": "in" },
    "body_mass": { "value": 180, "unit": "lb" },
    "age_years": 35,
    "sex": "male"
  },
  "splits": [
    {
      "label": "21 thrusters",
      "duration_seconds": 33,
      "work": {
        "movements": [
          {
            "movement": "thruster",
            "reps": 21,
            "inputs": {
              "external_load": { "value": 95, "unit": "lb" }
            },
            "spec_overrides": {}
          }
        ]
      }
    },
    {
      "label": "21 pull-ups",
      "duration_seconds": 27,
      "work": {
        "movements": [
          {
            "movement": "pull_up",
            "reps": 21,
            "spec_overrides": {}
          }
        ]
      }
    }
  ]
}

Response Shape

POST /v1/compute-power returns:

  • optional workout
  • results.session
  • results.splits[]
  • results.summary
  • results.movement_rollups[]
  • notes

Important semantics:

  • results.session reports session totals and elapsed/session-active power
  • results.splits[] reports per-split work and active-time power
  • results.summary captures peak, minimum, mean split power, dropoff, and consistency
  • results.movement_rollups[] preserves movement totals without inventing per-movement timing inside grouped splits
  • notes explains denominator and modeling assumptions

Stored Completed Workout Metadata

When evaluation_context=completed, successful POST /v1/compute-power responses now include:

  • workout.workout_id
  • workout.revision_id
  • workout.revision_number
  • workout.revision_status
  • workout.supersedes_revision_id

Additional Details

  • X-PowerOracle-Agent is an optional request header and is stored with successful compute events.
  • api_version and compute_model_version are server-managed and should not be sent by clients.
  • In MVP, only successful completed requests create stored workout history. planned and hypothetical requests compute results but do not create stored workouts.

POST /v1/workouts/{workout_id}/revisions

Use this route to correct a stored completed workout.

Required fields:

  • supersedes_revision_id
  • compute_request

Optional fields:

  • correction_reason

Rules:

  • compute_request.evaluation_context must be completed
  • compute_request.athlete_uuid must match the athlete for the target workout
  • supersedes_revision_id must be the current canonical revision for that workout

If the supplied revision is stale, the route returns 409 Conflict.

Successful responses use the same workout + results + notes shape as POST /v1/compute-power.

POST /v1/workouts/{workout_id}/void

Use this route when the current canonical workout should stop counting and there is not yet a corrected replacement.

Required fields:

  • supersedes_revision_id
  • void_reason

Behavior:

  • the current canonical revision becomes voided
  • the workout is removed from default history and analytics
  • no new compute result is created

This route returns workout state only, not compute results.

Example response:

{
  "workout": {
    "workout_id": "11111111-1111-1111-1111-111111111111",
    "workout_status": "voided",
    "voided_revision_id": "22222222-2222-2222-2222-222222222222"
  }
}

In production, compute-bearing routes are paid:

  • POST /v1/compute-power
  • POST /v1/workouts/\{workout_id\}/revisions

Operational rules:

  • first call may return 402 Payment Required
  • the x402 challenge arrives in PAYMENT-REQUIRED
  • the L402 challenge arrives in WWW-Authenticate: L402 ...
  • retry with PAYMENT-SIGNATURE: <x402 proof> or Authorization: L402 <token>:<preimage>
  • successful x402 responses include PAYMENT-RESPONSE
  • route price is $0.10 for POST /v1/compute-power and $0.04 for POST /v1/workouts/\{workout_id\}/revisions
  • x402 uses the USD-denominated exact price directly
  • L402 uses sats derived from the same USD route price with a cached live BTC/USD quote
  • authorized 2xx and 4xx responses settle or consume the payment, while 5xx responses do not
  • POST /v1/workouts/\{workout_id\}/void is free
  • If the live challenge or server behavior differs, treat the live server behavior as authoritative.

See Workout History And Corrections for the rationale and workflow, Calling Power Oracle from a Client for the operational flow, and Payments for the payment contract.

Next Step