DEVELOPER DOCS

REST API

Ship Check

On this page

Prompt versioning, typing, and evaluation — plus a zero-LLM PR gate. Ship Check treats prompts as versioned artifacts so a prompt change is reviewable like a code change, and catches regressions before they ship.


List prompts

HTTP
GET /v1/observ/orgs/{org}/workspaces/{ws}/shipcheck/prompts

Every prompt key seen in the window, with its current version and usage.

Auth: API key or JWT · Role: viewer

Query parameters

NameTypeRequiredDefaultDescription
daysinteger➖7Lookback window in days

Response 200 — not schema-modelled

JSON
{
  "prompts": [
    {
      "prompt_key": "checkout.system",
      "current_version": "v7",
      "version_count": 7,
      "call_count": 8120,
      "total_cost_usd": 141.20,
      "last_seen": "2026-09-01T14:23:05Z"
    }
  ]
}

Examples

p = evigauge.get("/v1/observ/orgs/{org}/workspaces/{ws}/shipcheck/prompts",
                 params={"days": 30})
for x in p["prompts"]:
    print(f"{x['prompt_key']:30} {x['current_version']:6} ${x['total_cost_usd']:.2f}")

List prompt versions

HTTP
GET /v1/observ/orgs/{org}/workspaces/{ws}/shipcheck/prompts/{prompt_key}/versions

Auth: API key or JWT · Role: viewer

Path parameters

NameTypeRequiredDescription
orgstring✅Organization slug
wsstring✅Workspace slug
prompt_keystring✅Prompt identifier, URL-encoded if it contains /

Query parameters

NameTypeRequiredDefaultDescription
daysinteger➖30Lookback window in days

Examples

from urllib.parse import quote
key = quote("checkout.system", safe="")
v = evigauge.get(
    f"/v1/observ/orgs/{{org}}/workspaces/{{ws}}/shipcheck/prompts/{key}/versions",
    params={"days": 90},
)
print(v)

Get one prompt version

HTTP
GET /v1/observ/orgs/{org}/workspaces/{ws}/shipcheck/prompts/{prompt_key}/versions/{version}

Auth: API key or JWT · Role: viewer

Path parameters

NameTypeRequiredDescription
org, wsstring✅Slugs
prompt_keystring✅Prompt identifier
versionstring✅Version identifier, e.g. v7

Query parameters

NameTypeRequiredDefaultDescription
daysinteger➖30Lookback window in days

Examples

d = evigauge.get(
    f"/v1/observ/orgs/{{org}}/workspaces/{{ws}}/shipcheck/prompts/{key}/versions/v7"
)
print(d)

Diff two prompt versions

HTTP
GET /v1/observ/orgs/{org}/workspaces/{ws}/shipcheck/prompts/{prompt_key}/diff

Text diff plus the behavioural delta — cost, latency and grade change — between two versions.

Auth: API key or JWT · Role: viewer

Query parameters

NameTypeRequiredDefaultDescription
from_versionstring✅—Baseline version
to_versionstring✅—Comparison version
daysinteger➖30Lookback window in days

Examples

diff = evigauge.get(
    f"/v1/observ/orgs/{{org}}/workspaces/{{ws}}/shipcheck/prompts/{key}/diff",
    params={"from_version": "v6", "to_version": "v7"},
)
print(diff)

Errors

StatusCause
422from_version or to_version omitted — both are required
404A named version does not exist inside the days window

Pipeline diff

HTTP
GET /v1/observ/orgs/{org}/workspaces/{ws}/shipcheck/pipeline/diff

What changed across the whole prompt pipeline in the window — every prompt whose version moved, and the aggregate effect.

Auth: API key or JWT · Role: viewer

Query parameters

NameTypeRequiredDefaultDescription
daysinteger➖7Lookback window in days

Examples

pd = evigauge.get("/v1/observ/orgs/{org}/workspaces/{ws}/shipcheck/pipeline/diff",
                  params={"days": 14})
print(pd)

Reprice a prompt

HTTP
POST /v1/observ/orgs/{org}/workspaces/{ws}/shipcheck/reprice

Recompute what a prompt's historical traffic would have cost on a different model. A pure what-if — it replays nothing and changes nothing.

Auth: API key or JWT · Role: viewer

Request body — RepriceBody

FieldTypeRequiredDefaultDescription
prompt_keystring✅—Prompt to reprice
modelstring✅—Target model id, e.g. claude-sonnet-4-6
providerstring➖""Provider hint when the model id is ambiguous
daysinteger➖30Window of historical traffic to reprice

Examples

rp = evigauge.post("/v1/observ/orgs/{org}/workspaces/{ws}/shipcheck/reprice", json={
    "prompt_key": "checkout.system",
    "model": "claude-sonnet-4-6",
    "days": 30,
})
print(rp)

Submit a candidate prompt

HTTP
POST /v1/observ/shipcheck/candidate

Evaluate a proposed prompt against the live baseline before shipping it. This is the endpoint the CI gate calls on a pull request.

Auth: API key only (x-opexia-api-key / dr_*) — this endpoint does not accept a JWT, because it is designed for CI. Workspace scope comes from the key, so there is no {org} / {ws} in the path.

Request body — CandidateBody

FieldTypeRequiredDefaultDescription
candidate_textstring✅—The proposed prompt text
prompt_keystring | null➖nullExisting prompt to compare against
namestring | null➖nullHuman label for the candidate
modelstring➖""Model the candidate targets
providerstring➖""Provider hint
daysinteger➖7Baseline window in days
policyobject➖{}Gate policy overrides (thresholds)

Examples

import httpx, os, pathlib

candidate = pathlib.Path("prompts/checkout.system.md").read_text()

r = httpx.post(
    "https://api.opexia.dev/v1/observ/shipcheck/candidate",
    headers={"x-opexia-api-key": os.environ["OPEXIA_API_KEY"]},
    json={
        "candidate_text": candidate,
        "prompt_key": "checkout.system",
        "model": "claude-opus-4-6",
        "days": 7,
    },
    timeout=120,
)
r.raise_for_status()
result = r.json()
# Fail the CI job when the gate does not pass.
if result.get("verdict") != "pass":
    raise SystemExit(f"Ship Check failed: {result}")

The opexia shipcheck CLI wraps this endpoint with policy loading and PR comment rendering — see the SDK reference.