Skip to content
Cloud Score Docs

Send requests through Cloud Score

Call POST /v1/requests with a gateway key: the request fields, the response envelope, status versus HTTP code, error types, SSE streaming, and the two GET endpoints.

WhereAdminDeveloperNeeds a gateway keyNeeds a connected providerNeeds an enabled modelOpen in Cloud Score
On this page

Prompt Optimization: optimize, review, then run

Prompt Optimization has one ON/OFF control, defaults ON, and accepts any prompt length. In Playground, Optimize prompt prepares a complete optimized prompt before answer routing, at the level you pick — Standard, Balanced or Thorough. Live counts use a real backend tokenizer. Review the original, optimized version and diff, then choose Run original or Run optimized. Our checks cannot guarantee that meaning is preserved, which is why you review the result. Editing the request invalidates its comparison. Workspace defaults are under Optimization › Settings.

For an interactive native flow, POST the full request to /v1/prompt-optimizations/prepare as {"request_type":"native","request":{...}} using the same bearer execution key. Include authoring options with the optimization strength (deterministic, balanced or aggressive) and the editable message indices. Then send the unchanged source request to /v1/requests with constraints.prompt_optimization containing enabled, proposal_id, the sealed proposal_token and choice (original or optimized). Use a distinct Idempotency-Key for preparation and execution. Keep the sealed token in memory only. Explicit {"enabled":false} preserves the original. Legacy compression fields are deprecated compatibility aliases; do not combine conflicting old and new controls.

Playground explicitly requests a bounded optimization and shows its recorded cost. A rejected, unavailable or unhelpful result falls back to your original without hiding its expense. Requests sent ON without a prepared proposal are optimized by structural rules only. Comparison details show the outcome, the rules applied and the measured work time. Infrastructure still consumes resources; unallocated compute keeps fully loaded savings unknown. Historical optimization expenses remain recorded and are not reset to zero.

The execution receipt distinguishes the selected prompt from the prompt actually sent for the answer, including no provider send when a cache supplies it. Optimization can have a recorded cost even when the original is selected or no answer is generated. Unknown infrastructure cost keeps fully loaded net unknown. Fewer tokens do not establish a latency or quality improvement. Analytics, ROI and Reports reuse Prompt Optimization evidence with production/demo filters and daily, weekly and monthly views.

See Playground for comparison and recovery, and Analytics for measurement coverage. Historical compression receipts do not establish choices or costs that were never recorded.

The endpoint

The native endpoint is POST /v1/requests. Your application sends one input and, optionally, constraints; Cloud Score classifies it, picks a model, calls it with retries and failover, checks the answer, and returns an envelope that says what happened and what it cost. Every call is logged and appears in Logs.

Your app

POST /v1/requests with a dex_sk_ key

Cloud Score pipeline

classify, match, policy, cache, select, execute, guard, validate

Envelope

id, status, output, routing, usage, error

The same four endpoints are listed in the app under Admin › Developer › Endpoints, with the purposes below. This page covers the three native ones; the OpenAI-compatible one has its own page.

MethodPathPurpose
POST/v1/requestsNative API — strategies, constraints, decision trace, SSE streaming.
GET/v1/requests/{id}Retrieve a past request with its full routing trace.
POST/v1/chat/completionsOpenAI-compatible. model: "auto" routes; a concrete name pins.
GET/v1/modelsModels enabled for your workspace, with capabilities and pricing.

Authenticate

Send a gateway key on every request as Authorization: Bearer dex_sk_…. Keys are created under Admin › API keys with Create key and shown once; the key decides the workspace, the security profile, the budget, body storage, and the sandbox flag a request runs under.

HeaderDirectionWhat it does
Authorization: Bearer dex_sk_…request, requiredAuthenticates the call. Invalid and disabled keys get the same 401 with the message missing or invalid API key.
Content-Type: application/jsonrequestThe body is JSON.
X-Dex-Error-Status: http|enveloperequest, optionalChooses the status contract for this one request. See Status versus HTTP code.
X-Dex-Cache-Control: no-cache|no-storerequest, optionalThe cache directive as a header, with the same two bypass values as constraints.cache.
X-Dex-team, X-Dex-application, X-Dex-agent, X-Dex-environment, X-Dex-end-userrequest, optionalHeader form of metadata for cost attribution. The body wins over these headers; these headers win over the key's stored defaults.
X-Dex-Status-Contract: envelope|httpresponse, alwaysNames the contract that produced the response, so a client never has to infer it.
X-Dex-Budget-State: ok|soft|hard|error|noneresponse, non-streamThe budget verdict for this request. The Playground does not read it.

Every authenticated call updates the key's last-used timestamp, is policy-checked, logged, and billed. Revoke and re-create keys from Admin › API keys. Keys carry no per-model restrictions; model availability is workspace-level.

The request body

Only input is required. Everything else narrows or annotates the request. A body that sends a cost-first strategy, a cost cap, a JSON requirement, and attribution tags:

POST /v1/requests
{
  "input": "Summarize this quarterly update in three bullets: …",
  "constraints": {
    "strategy": "cost",
    "max_cost_usd": "0.005",
    "required_capabilities": ["json_mode"]
  },
  "response_format": { "type": "json_object" },
  "stream": false,
  "metadata": { "team": "growth", "application": "onboarding-bot" }
}
FieldValuesWhat it does
inputstring, requiredThe text to classify and route.
intentstring, optionalOptional free text, returned by GET /v1/requests/{id}.
constraints.strategyauto · balanced · cost · intelligence · latencyOverrides the scoring weights for this request. auto is no override and defers to policies and workspace defaults; balanced pins 40 / 20 / 40 even where a policy prefers a tier. See Routing strategies.
constraints.qualitylow · balanced · highMaps to the cost, balanced, and quality presets. An explicit constraints.strategy takes precedence.
constraints.max_cost_usddecimal, as a stringRules out candidates priced above it; the lower of this and a policy cap applies. With nothing left the request fails no_candidates.
constraints.max_latency_msintegerLowers the request deadline and, when no constraints.quality is sent, applies the latency preset. Running out of time ends the request deadline_exceeded.
constraints.model_overridea model keyPins one model and disables cross-model failover. An unknown or disabled key ends no_candidates.
constraints.required_capabilitiesjson_mode · streaming · tools · visionAdded to what the classifier infers; models lacking them are excluded at Match. An unknown value is a 422.
constraints.policy_idslist of policy idsEvaluate only these policies. Sandbox keys only, otherwise a 403 policy selection requires a sandbox API key. An empty list means no policies; the budget gate always runs.
constraints.cachedefault · no-cache · no-storeno-store: nothing is read or written. no-cache: the lookup is skipped, the write-back is kept. Recorded as bypass_no_store / bypass_no_cache.
response_formatjson_object · json_schemaAdds the json_mode capability, turns on validation with one re-prompt, and disables the semantic cache. A failed re-prompt ends validation_failed with partial_output.
streambooleanSwitches the response to SSE. See Stream with SSE.
metadatateam · application · agent · environment · end_userCost attribution tags, echoed back as routing.attribution. Other keys are ignored; values are capped at 120 characters.

Pinning a model removes failover.

The app's Explicit model mode warns: Pinning a model disables cross-model failover — a hard provider failure fails the request instead of rerouting. Availability is workspace-level; keys don't carry per-key model restrictions.

The response envelope

The envelope is the same for a routed answer, a cache hit, a block, and a failure. The sample below is the one the app shows under Admin › Developer › Response envelope.

200 OK
{
  "id": "req_5f8e6d2a-…",
  "status": "completed",
  "output": "• Revenue grew 18% QoQ…",
  "routing": {
    "model": "gpt-4o-mini",
    "provider": "openai",
    "classifier": "llm",
    "task_type": "summarization",
    "complexity": 2,
    "candidates_considered": 6,
    "attempts": 1
  },
  "usage": {
    "input_tokens": 412,
    "output_tokens": 96,
    "cost_usd": 0.000119,
    "latency_ms": 842
  }
}
MemberMeaningWhen absent
idThe request id, prefixed req_…. Use it with GET /v1/requests/{id} and to find the row in Logs.never
statuscompleted, blocked, or failed. The outcome lives here, not in the HTTP code.never
outputThe answer. On a stream, the value here is authoritative over the deltas you were shown.null when nothing was delivered, for example a block at Guard out
routing.model, routing.providerThe model that answered and its provider.null when the request ended before a model was selected
routing.classifierWhere the classification came from: llm, cache, or heuristic.null when not classified
routing.task_type, complexityThe classified task type and its 1 to 5 complexity.null when not recorded
candidates_consideredHow many enabled models passed the capability and context-window filter.null when not recorded
routing.attemptsBilled provider calls, counting failover, the validation re-prompt, and the output-budget rollback. Same-model transient retries do not count.never; 0 is a real count
routing.cachestatus (hit / miss / ineligible / off), source (exact / semantic), reason, similarity. See Caching and deduplication.similarity only on semantic paths
routing.attribution, routing.budget, routing.optimizationThe resolved attribution tags, the budget verdict, and the optimization plan summary.not in the static sample; added by the backend when present
usage.input_tokens, usage.output_tokensTokens billed across every provider call.null, for example when blocked before execution
usage.cost_usdMeasured list-price cost. A served cache hit is 0.null when blocked before execution
usage.latency_msEnd-to-end latency.null when not recorded
usage.saved_usd, usage.saved_tokensWhat serving from the response cache avoided, estimated at the producing model's price.only on cache hits; stripped if Guard out blocks the hit
usage.cached_input_tokens, usage.provider_saved_usdProvider-side prompt-cache reads and the estimated discount.only when the provider reported cached reads
usage.reasoning_tokensReasoning tokens, where the provider reports them.null when the provider reports none
securityWhat AI Security did to the prompt and the answer under the key's profile.null when not recorded
error.type, error.messageWhy the request is blocked or failed. See Error types.absent when status is completed

Money is a float here.

usage.cost_usd, usage.saved_usd, and usage.provider_saved_usdare JSON floats on this endpoint, a grandfathered exception to the platform's rule that money is a decimal string. Everything the admin app shows about the same request uses decimal strings.

Status versus HTTP code

Check the envelope, not the HTTP code.

The app states the rule as: The native API answers HTTP 200 even for failed requests — the outcome lives in status. Always check the envelope, not the HTTP code.

That is the default contract, envelope. A key, or one request, can opt into real status codes with the http contract. Either way the response header X-Dex-Status-Contract names which one applied, and under http a non-2xx body is still the full envelope.

ContractHow it is chosenWhat you get
envelopeThe default when neither the request header nor the key says otherwise. Streams always use it.HTTP 200 for every settled request; read status and error.type.
httpSend X-Dex-Error-Status: http, or have the key's stored default set to it. The request header wins over the key.403 for blocked, 409 for no_candidates, 502 for provider_error and validation_failed, 504 for deadline_exceeded, each with the full envelope as the body.

no_candidates maps to 409, not a 5xx, so an SDK retry policy does not amplify a deterministic configuration failure. Plain 400, 401, 403, 404, and 422 responses (a bad key, a non-sandbox key sending constraints.policy_ids, an unknown request id, a malformed body) are not envelopes; they carry a message only.

Error types

error.type says which stage gave up; error.messageis the stage's own text. The four types the app lists under Response envelopeare quoted with the app's meaning; the last two are recorded the same way.

error.typeEnvelope statusMeaningMessages you will see
no_candidatesfailedNo enabled model satisfies the constraints (including an unknown or disabled pinned model).no enabled model matches the required capabilities and context window (at Match) or no candidate models remain after constraints, policies, and failover exclusions (at Select).
blockedblockedA routing policy or budget blocked the request before execution.blocked by policy '<name>' (or the policy's own message), or budget exhausted: <scope> <scope_value> at <utilization_pct>% (model_spend).
provider_errorfailedEvery eligible model failed after retries and failover.<model_key>: <scrubbed provider error>, truncated to 300 characters and scrubbed of secrets.
validation_failedfailedThe output failed validation; a partial_output preview is included.empty response, or response failed schema validation. partial_output holds the first 500 characters unless a security profile enforces output.
security_blockedblockedAI Security blocked the prompt at Guard in or withheld the answer at Guard out.The profile's own blocked reason, else blocked by AI Security. See AI Security.
deadline_exceededfailedThe request deadline ran out before another billed attempt could start. Does not fail over.<model_key>: request deadline exhausted before another attempt could start.

Stream with SSE

Send stream true and the response is text/event-stream. Frames use the format event: <name>\ndata: <json>\n\n. Five event names occur; the Playground's Stream the answer option uses the same stream to draw the stations in Details › Routing.

EventDataWhat to do with it
dex_traceOne event per pipeline stage: stage, at, ms, detail. Never retracted.Optional. Render progress, or ignore. The generated SDK snippets skip it.
delta{text}, settled output only.Append to what you show.
resetA reason: validation_failed, provider_error, or output_budget_rollback.Discard everything shown so far; a re-prompt, failover, or rollback follows. The Playground shows Output failed validation. Retrying… or Attempt failed. Rerouting….
doneThe full envelope.Authoritative. Replace the streamed text with output and check status.
error{message}, only on an unexpected pipeline crash; the message is internal error.Treat as a failed request.

A stream can end without done.

A dropped connection closes the stream with no final event. Treat a stream that ends without done or error as failed; the Playground reports it as stream closed before completion. Closing the connection from your side does not cancel the request: it finishes, is recorded, and is billed server-side.

Streams always use the envelopecontract. When the key's security profile enforces output (a redact or block action on any output category), live deltas are switched off and the answer arrives in one piece after Guard out settles; the Playground shows the Guard in station as buffered.

Retrieve a request and list models

CallReturnsNotes
GET /v1/requests/{id}The recorded request: status, output, intent, classification, usage, error, and the full trace (the same stations Logs draws).An unknown id is a 404 with request not found. The Playground calls this after a non-streaming send to fill Details › Routing.
GET /v1/modelsA list envelope, "object": "list", whose data rows carry id, object, owned_by, display_name, capabilities, context_window, and pricing as strings.Workspace-scoped: the models enabled under Models, which is the set constraints.model_override may pin.

Examples

Cheapest JSON-capable model under a cap

What you do

Send the body shown above: constraints.strategy cost, constraints.max_cost_usd 0.005, constraints.required_capabilities json_mode.

What Cloud Score does

Keeps only enabled models that can emit JSON, drops any priced above $0.005, scores the rest with the cost preset (70% cost · 10% latency · 20% quality), calls the winner, and validates the answer parses.

What you see

HTTP 200 with status completed and the winner in routing.model. If every JSON-capable model costs more than the cap: status failed, error.type no_candidates, and the message no candidate models remain after constraints, policies, and failover exclusions.

Real HTTP codes for a retry policy

What you do

Add the header X-Dex-Error-Status: http to every call and retry only on 502 and 504.

What Cloud Score does

Answers a policy or budget block with 403, an empty candidate set with 409, an exhausted failover or failed validation with 502, and an exhausted deadline with 504, each with the full envelope as the body.

What you see

X-Dex-Status-Contract http on every response. A 409 no_candidates is not retried, because it will not change until the workspace does; a 502 provider_error is.

Good to know

Three billed attempts per request.

Failover, the validation re-prompt, and the output-budget rollback share the cap of 3 billed provider calls; same-model transient retries (up to 2, after 0.5 s and 1.0 s) do not count. Setup failures that never reach a provider have their own cap of 6 and bill nothing. routing.attempts reports the billed count.

auto defers, balanced pins.

constraints.strategy auto inherits a policy's preferred tier and the sliders under Admin › Organization; balanced and constraints.quality balanced both pin 40 / 20 / 40. Only an absent constraint defers. A strategy changes scoring only: blocks, allow and deny lists, forced models, cost caps, budgets, and guards still apply.

Sandbox keys and policy selection.

constraints.policy_ids is accepted only from a key created with Sandbox key — may hand-pick policies per request (playground) checked; other keys get a 403. It narrows which policies are evaluated, never the budget gate.

Unknown capabilities are rejected.

An unknown capability in constraints.required_capabilities is a 422.

Try it before wiring code.

The Playground sends this endpoint with input, system, stream, and the constraints strategy, quality, max_cost_usd, max_latency_ms (Fast), required_capabilities, cache, prompt_optimization and, for sandbox keys, policy_ids, each only when set, and shows every dex_trace event in Details › Routing. Admin › Developer generates a Cloud Score client for Python, TypeScript, or Go that sends the body and parses the stream for you.

Related