{"openapi":"3.1.0","info":{"title":"Locus Pro API","description":"Production is live at https://api.paywithlocus.com/api. Stage remains available for evaluation and integration testing at https://api.stage.paywithlocus.com/api; credentials, balances, and tenant data are isolated by environment. Embedded prepaid credits over the Locus pay-per-use catalog. Money and top-up amounts use exact decimal strings (up to 6dp). Every burn requires an Idempotency-Key header. Management routes accept a tenant secret key or authorized dashboard session as shown per operation. High-risk operations protected by workspace-administrator step-up require an owner or admin dashboard session, the applicable scope, and MFA/passkey authentication completed in the last ten minutes; developer, billing, viewer, and secret-key principals remain ineligible even when a matching scope is present. Scoped secret keys retain only the explicitly documented Agent Connection lifecycle exception. Widget routes accept an end-user JWT alone; when a publishable key is present it must belong to the JWT's tenant. MCP uses OAuth 2.1 Authorization Code with PKCE by default and also accepts the explicitly documented tenant secret key, end-user JWT, or scoped agent connection compatibility credentials. Burns accept the execution credentials shown per operation. Publishable keys never authorize management or burns by themselves.","version":"0.7.0"},"servers":[{"url":"https://api.paywithlocus.com/api","description":"Production"},{"url":"https://api.stage.paywithlocus.com/api","description":"Stage — evaluation and integration testing"}],"security":[{"secretKey":[]}],"tags":[{"name":"Authentication","description":"Email-verified self-serve account creation and dashboard identity"},{"name":"Tenants","description":"Tenant profile, keys, and settings (dashboard session or secret key)"},{"name":"Workspace members","description":"Invite-only human workspace membership and role administration"},{"name":"Catalog","description":"Enable/disable APIs and set markups"},{"name":"Custom APIs","description":"Feature-gated enterprise BYOK providers and schema-backed custom actions"},{"name":"End users","description":"End-user accounts, tokens, and allocations"},{"name":"Customers","description":"Names for the customers a tenant attributes spend to, and every customer's spend"},{"name":"Top-ups","description":"Locus-hosted checkout top-ups and quotes"},{"name":"Ledger","description":"Burn/top-up history and earnings"},{"name":"Webhooks","description":"Signed events, delivery inspection, and replay"},{"name":"Burn","description":"Metered pay-per-use calls"},{"name":"Travel routing","description":"Feature-gated multi-provider flight search, no-dispatch planning, and feedback"},{"name":"MCP","description":"Stateless Streamable HTTP transport and MCP tool-result contracts"},{"name":"Okibi Identity","description":"Feature-gated Okibi identity verification and scoped native CLI credential bootstrap"},{"name":"Widget","description":"End-user JWT surface; a matching publishable key is optional"},{"name":"Agent-native onboarding","description":"Self-registration, human Stripe funding handoff, and restricted account setup for headless agents"},{"name":"Hosted Workflows","description":"Tenant-private TypeScript Workflow definitions, immutable versions, bounded runs, artifacts, and recovery"},{"name":"Resources","description":"Durable resources an agent bought, such as phone numbers, inboxes and sandboxes"}],"paths":{"/credits/plans":{"get":{"tags":["Tenant"],"summary":"Read monthly plan and Enterprise trial status","operationId":"getCreditsPlanStatus","description":"Requires a human workspace session with tenant:read. Trial expiry pauses Enterprise features without erasing prepaid balances or changing the assigned usage rate. Complete paid Enterprise checkout to restore those features; a top-up does not extend the trial.","security":[{"dashboardSession":[]}],"parameters":[{"name":"refresh","in":"query","schema":{"type":"boolean","default":false},"description":"Reconcile the current Stripe subscription before returning the plan."}],"responses":{"200":{"description":"Current subscription, trial deadline and checkout availability","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true},"enterpriseTrial":{"oneOf":[{"type":"null"},{"type":"object","required":["status","startedAt","endsAt"],"properties":{"status":{"enum":["active","expired"]},"startedAt":{"type":"string","format":"date-time"},"endsAt":{"type":"string","format":"date-time"}},"description":"A stored Enterprise trial: 7 days for an invited workspace, 14 for an operator upgrade. Paid conversion clears the visible trial, preserves its audit dates and keeps the assigned usage-pricing profile."}]},"enabled":{"type":"boolean"},"currentPlan":{"enum":["free","plus","enterprise","enterprise_plus"]},"legacy":{"type":"boolean"},"checkoutConfigured":{"type":"boolean"},"includedBalanceUsd":{"type":"string"},"includedExpiresAt":{"type":["string","null"],"format":"date-time"}}}}}},"403":{"description":"Human workspace membership is required"}}}},"/credits/tools/execute":{"post":{"tags":["Tool discovery"],"summary":"Execute a tool with an optional approved quote","operationId":"executeCreditsTool","description":"Uses the same approval, spending limits, idempotency and billing result as MCP execute. max_credits caps the charge (409 charge_ceiling_exceeded, nothing charged). When a spending policy returns an approval_token and idempotency_key, send both with the identical slug, customer and args. HTTP 200 means the execution envelope was delivered; inspect result.isError and its billing metadata before treating the call as successful. Sandbox credentials are not supported.","security":[{"secretKey":[]},{"agentConnection":[]},{"endUserToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","idempotency_key"],"additionalProperties":false,"properties":{"slug":{"type":"string"},"args":{"type":"object","additionalProperties":true},"approval_token":{"type":"string","maxLength":4096},"max_credits":{"type":["string","number"],"description":"Most credits this call may charge."},"idempotency_key":{"type":"string","minLength":1,"maxLength":200},"loop_id":{"type":"string","maxLength":200},"attribution":{"type":"object","additionalProperties":{"type":"string"}}}}}}},"responses":{"200":{"description":"MCP-compatible tool result, including success or failure and charge metadata","content":{"application/json":{"schema":{"type":"object","required":["success","result"],"properties":{"success":{"const":true},"result":{"type":"object","properties":{"isError":{"type":"boolean"},"content":{"type":"array","items":{"type":"object"}},"structuredContent":{"type":"object"},"_meta":{"type":"object","additionalProperties":true}}}}}}}},"400":{"description":"Invalid execution request"},"401":{"description":"Invalid credentials"},"403":{"description":"Execution is not permitted"}},"parameters":[{"name":"X-Locus-End-User","in":"header","schema":{"type":"string"},"description":"For a trusted workspace credential, select the same customer used for the approval. A customer-bound credential cannot select another account."}]}},"/credits/okibi/cli-credential":{"get":{"tags":["Okibi Identity"],"summary":"Read Okibi CLI credential bootstrap status","operationId":"getCreditsOkibiCliCredential","description":"A real Okibi-protected resource used to verify the signed CLI release, active identity grant, durable Locus account binding, and current installation credential state. It never returns the raw native credential. The account block names the linked Locus user and whether that user still has to choose a password. Requires both mcp:read and mcp:execute from Okibi Identity.","security":[{"okibiIdentity":[]}],"responses":{"200":{"description":"Verified installation and current native credential state","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["success","identityProvider","installationId","account","credentialConfigured","connection","bootstrap"],"properties":{"success":{"const":true},"identityProvider":{"const":"okibi"},"installationId":{"type":"string"},"account":{"$ref":"#/components/schemas/OkibiLinkedAccount"},"credentialConfigured":{"type":"boolean"},"connection":{"oneOf":[{"$ref":"#/components/schemas/OkibiCliConnectionMetadata"},{"type":"null"}]},"bootstrap":{"type":"object","additionalProperties":false,"required":["method","registrationToken","tools"],"properties":{"method":{"const":"POST"},"registrationToken":{"type":"string"},"tools":{"type":"string"}}}}}}}},"401":{"description":"Missing, invalid, expired, or inactive Okibi capability"},"403":{"description":"Missing mcp:read/mcp:execute or inactive Locus membership"}}},"post":{"tags":["Okibi Identity"],"summary":"Bootstrap a scoped Locus CLI credential from Okibi Identity","operationId":"postCreditsOkibiCliCredential","description":"Exchanges a verified Okibi identity grant for one Locus lcac_ execution credential bound to the Okibi identity, CLI installation, and selected workspace. The credential expires 7 days after its last use and never later than 30 days after issue; every bootstrap issues it fresh for 7 days. Generate registrationToken locally from exactly 24 random bytes encoded as unpadded base64url. Replaying the token renews the installation's credential unchanged; a new token rotates that credential in place (same connection, new secret and prefix). A revoked credential is never renewed or rotated. When tools is present the server enables exactly those catalog slugs and restricts the credential to them; when it is omitted the credential may use every endpoint the workspace has enabled, and a fresh bootstrap may replace or lift an existing allowlist. The token is never stored; Locus stores only the derived credential hash.","security":[{"okibiIdentity":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["registrationToken"],"properties":{"registrationToken":{"$ref":"#/components/schemas/AgentRegistrationToken"},"tools":{"type":"object","additionalProperties":false,"required":["enable"],"description":"Optional endpoint allowlist. Omit it to leave the credential unrestricted within the workspace's enabled endpoints.","properties":{"enable":{"type":"array","minItems":1,"maxItems":200,"uniqueItems":true,"items":{"type":"string","pattern":"^[^/\\s]+/[^/\\s]+$","description":"Exact provider/endpoint catalog slug, for example apollo/people-search."}}}}}}}}},"responses":{"200":{"description":"Existing credential renewed (same token) or rotated in place (new token); rotated tells which","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkibiCliCredentialEnvelope"}}}},"201":{"description":"New native credential created for this installation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkibiCliCredentialEnvelope"}}}},"400":{"description":"Invalid registration token, empty endpoint allowlist, or unknown field"},"401":{"description":"Missing, invalid, expired, or inactive Okibi capability"},"403":{"description":"Missing mcp:read/mcp:execute or inactive Locus membership"},"404":{"description":"Unknown provider/endpoint catalog slug"},"409":{"description":"The installation's native credential was revoked in the dashboard, or the registration token already belongs to another installation"}}}},"/credits/cli/credential":{"get":{"tags":["Authentication"],"summary":"Read Locus CLI credential status","operationId":"getCreditsCliCredential","description":"Reads the lcac_ credential bound to the caller's Locus OAuth connection. It never returns the raw credential. Send a Locus MCP OAuth access token with mcp:read and mcp:execute, issued to the Locus CLI client.","security":[{"mcpOAuth":["mcp:read","mcp:execute"]}],"responses":{"200":{"description":"Current credential state for this OAuth connection","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["success","identityProvider","installationId","account","credentialConfigured","connection","bootstrap"],"properties":{"success":{"const":true},"identityProvider":{"const":"locus-oauth"},"installationId":{"type":"string"},"account":{"$ref":"#/components/schemas/OkibiLinkedAccount"},"credentialConfigured":{"type":"boolean"},"connection":{"oneOf":[{"$ref":"#/components/schemas/OkibiCliConnectionMetadata"},{"type":"null"}]},"bootstrap":{"type":"object","additionalProperties":false,"required":["method","registrationToken","tools"],"properties":{"method":{"const":"POST"},"registrationToken":{"type":"string"},"tools":{"type":"string"}}}}}}}},"401":{"description":"Missing, invalid, or expired Locus OAuth access token"},"403":{"description":"Missing mcp:execute, or the signed-in account can no longer act for the workspace"}}},"post":{"tags":["Authentication"],"summary":"Exchange a Locus OAuth token for a scoped CLI credential","operationId":"postCreditsCliCredential","description":"Exchanges a Locus MCP OAuth access token (mcp:read and mcp:execute) for one lcac_ execution credential bound to that OAuth connection. Refreshing the OAuth token keeps the same binding. The credential expires 7 days after its last use and never later than 30 days after issue. It stops working when the signed-in account loses execute access to the workspace. Generate registrationToken locally from exactly 24 random bytes encoded as unpadded base64url. Replaying the token renews the credential unchanged; a new token rotates it in place. A revoked credential is never renewed or rotated. tools behaves as on the Okibi route. hostname is optional and names the credential \"Locus CLI (<hostname>)\" in the dashboard.","security":[{"mcpOAuth":["mcp:read","mcp:execute"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["registrationToken"],"properties":{"registrationToken":{"$ref":"#/components/schemas/AgentRegistrationToken"},"tools":{"type":"object","additionalProperties":false,"required":["enable"],"description":"Optional endpoint allowlist. Omit it to leave the credential unrestricted within the workspace's enabled endpoints.","properties":{"enable":{"type":"array","minItems":1,"maxItems":200,"uniqueItems":true,"items":{"type":"string","pattern":"^[^/\\s]+/[^/\\s]+$","description":"Exact provider/endpoint catalog slug, for example apollo/people-search."}}}},"hostname":{"type":"string","minLength":1,"maxLength":64,"description":"Optional machine name shown in the dashboard. Control characters are removed."}}}}}},"responses":{"200":{"description":"Existing credential renewed (same token) or rotated in place (new token); rotated tells which","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkibiCliCredentialEnvelope"}}}},"201":{"description":"New native credential created for this installation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkibiCliCredentialEnvelope"}}}},"400":{"description":"Invalid registration token, empty endpoint allowlist, or unknown field"},"401":{"description":"Missing, invalid, or expired Locus OAuth access token"},"403":{"description":"Missing mcp:execute, or the signed-in account is not an active member of the workspace"},"404":{"description":"Unknown provider/endpoint catalog slug"},"409":{"description":"The installation's native credential was revoked in the dashboard, or the registration token already belongs to another installation"}}}},"/credits/agent/onboarding":{"get":{"tags":["Agent-native onboarding"],"summary":"Read the agent-native onboarding contract","operationId":"getCreditsAgentOnboarding","description":"Public machine-readable flow for a headless agent. No existing Locus tenant is required. AgentID verification creates identity friction before any durable account exists; the human is needed only for an optional AgentMail OTP and the later Stripe funding handoff.","security":[],"responses":{"200":{"description":"Current onboarding steps, URLs, and security boundaries"}}}},"/credits/agent/register":{"post":{"tags":["Agent-native onboarding"],"summary":"Begin or complete verified agent-owned signup","operationId":"postCreditsAgentRegister","description":"A first request creates only a 30-minute pending row and returns an AgentID authorization URL. After AgentID PKCE verification, replaying the same name and registrationToken creates or recovers one zero-balance personal account and returns its scoped connection credential. The verified provider/subject pair is the durable one-account boundary. No free or bonus credits are issued.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentNativeRegistrationRequest"}}}},"responses":{"200":{"description":"Existing verified account replayed, renewed, or recovered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentOwnedAccountEnvelope"}}}},"201":{"description":"Verified agent-owned account created at a zero balance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentOwnedAccountEnvelope"}}}},"202":{"description":"Only a short-lived pending signup exists; AgentID verification is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSignupPendingEnvelope"}}}},"409":{"description":"The token is bound to different account details"},"429":{"description":"Registration rate limit exceeded"}}}},"/credits/agent/signup":{"post":{"tags":["Agent-native onboarding"],"summary":"Create an agent account with the human owner's email","operationId":"postCreditsAgentSignup","description":"Ask the human before using this route. Creates a new zero-balance agent workspace and returns its scoped lcac_ connection credential at once. The named human receives a one-time claim link; opening it makes them an owner of every pending agent account for that address, and \"This wasn't me\" suspends them. Replaying the same email, name, and registrationToken returns the same workspace and credential. Every new token creates a new workspace; an existing workspace is never joined by email. No free or bonus credits are issued.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentEmailSignupRequest"}}}},"responses":{"200":{"description":"Existing signup replayed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentOwnedAccountEnvelope"}}}},"201":{"description":"Agent workspace created at a zero balance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentOwnedAccountEnvelope"}}}},"400":{"description":"Invalid email, name, or registration token"},"403":{"description":"New accounts are invitation-only in this environment"},"409":{"description":"The token is bound to different account details"},"429":{"description":"Too many unclaimed accounts for this email, or too many signups from this network"}}}},"/credits/agent/claims/preview":{"post":{"tags":["Agent-native onboarding"],"summary":"Describe a claim link","operationId":"postCreditsAgentClaimsPreview","description":"Returns the owner email and every pending agent workspace the claim link covers.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentClaimTokenRequest"}}}},"responses":{"200":{"description":"Claim details"},"404":{"description":"Unknown claim link"},"410":{"description":"Claim link expired, already claimed, or declined"}}}},"/credits/agent/claims/accept":{"post":{"tags":["Agent-native onboarding"],"summary":"Claim agent accounts","operationId":"postCreditsAgentClaimsAccept","description":"Makes the address's owner an owner of each selected pending agent workspace for it (workspaceIds from preview). Other agents may have named the same address, so unselected workspaces stay pending. A new person receives a one-time passwordSetupToken for the set-password screen; an existing account is only added as an owner and signs in as usual.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentClaimDecisionRequest"}}}},"responses":{"200":{"description":"Workspaces claimed"},"400":{"description":"No workspace selected (CLAIM_SELECTION_REQUIRED)"},"404":{"description":"Unknown claim link"},"409":{"description":"A selected workspace is no longer pending (CLAIM_SELECTION_STALE)"},"410":{"description":"Claim link expired, already claimed, or declined"}}}},"/credits/agent/claims/decline":{"post":{"tags":["Agent-native onboarding"],"summary":"Decline agent accounts","operationId":"postCreditsAgentClaimsDecline","description":"\"This wasn't me\": suspends each selected pending agent workspace for the address and revokes its agent credentials and MCP connections.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentClaimDecisionRequest"}}}},"responses":{"200":{"description":"Workspaces suspended"},"400":{"description":"No workspace selected (CLAIM_SELECTION_REQUIRED)"},"404":{"description":"Unknown claim link"},"409":{"description":"A selected workspace is no longer pending (CLAIM_SELECTION_STALE)"},"410":{"description":"Claim link expired, already claimed, or declined"}}}},"/credits/agent/identity/agentid":{"get":{"tags":["Agent-native onboarding"],"summary":"Read the Locus AgentID client descriptor","operationId":"getCreditsAgentIdentityAgentid","description":"Public, unauthenticated. Returns the OpenID client descriptor Locus uses with AgentID, including the callback URL and the canonical skill URL an agent needs to start AgentID onboarding.","security":[],"responses":{"200":{"description":"OpenID client, callback, and canonical skill URLs"}}}},"/credits/agent/identity/agentid/callback":{"get":{"tags":["Agent-native onboarding"],"summary":"Complete AgentID authorization-code verification","operationId":"getCreditsAgentIdentityAgentidCallback","description":"Exchanges an AgentID authorization code with PKCE, verifies ES256 issuer, audience, nonce, stable subject, and live inbox, and marks the pending signup identity-verified. The callback never returns a Locus credential; the agent replays POST /credits/agent/register to receive it. This is the only AgentID callback: an MCP authorization started at /credits/mcp/oauth/authorize/agentid returns here with its lmo_req_ state and is redirected to the MCP client's registered callback with an authorization code or OAuth error.","security":[],"parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","required":true,"schema":{"type":"string","pattern":"^([A-Za-z0-9_-]{43}|lmo_req_[A-Za-z0-9_-]{43})$"}},{"name":"iss","in":"query","required":true,"schema":{"type":"string","const":"https://auth.agentid.com"},"description":"Required RFC 9207 authorization-response issuer; it must match the trusted AgentID issuer."}],"responses":{"200":{"description":"Static success page; replay registration to activate"},"400":{"description":"Invalid, denied, expired, or unverifiable AgentID callback"},"503":{"description":"AgentID or signup configuration is temporarily unavailable"}}}},"/credits/agent/account":{"get":{"tags":["Agent-native onboarding"],"summary":"Read the agent-owned account","operationId":"getCreditsAgentAccount","description":"Returns only the authenticated self-registered account, its usable pooled balance, expiry, links, and next action. Tenant-managed agent connections are rejected.","security":[{"agentConnection":[]}],"responses":{"200":{"description":"Agent-owned account state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentOwnedAccountEnvelope"}}}},"403":{"description":"The credential belongs to a tenant-managed connection"}}}},"/credits/agent/claim/resend":{"post":{"tags":["Agent-native onboarding"],"summary":"Resend the claim email","operationId":"postCreditsAgentClaimResend","description":"Emails the human owner a fresh claim link unless the address received one in the last 10 minutes or three in the last day. The new link replaces this account's previous one. With email, an unclaimed account's owner address is corrected first and the old link stops working.","security":[{"agentConnection":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"email":{"type":"string","format":"email","maxLength":320}}}}}},"responses":{"200":{"description":"Claim email sent, recently sent, or already resolved"},"400":{"description":"The account was not created with an owner email, or the email is invalid"},"403":{"description":"Signup is closed for the new address"},"409":{"description":"The account was already claimed, so its owner email cannot change"},"429":{"description":"Rate limit exceeded"}}}},"/credits/agent/credential/rotate":{"post":{"tags":["Agent-native onboarding"],"summary":"Rotate the agent-owned credential","operationId":"postCreditsAgentCredentialRotate","description":"Atomically replaces the account recovery digest and bearer credential from a newly generated 24-byte base64url token, then extends expiry by 365 days.","security":[{"agentConnection":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["registrationToken"],"properties":{"registrationToken":{"$ref":"#/components/schemas/AgentRegistrationToken"}}}}}},"responses":{"200":{"description":"Credential rotated and returned once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentOwnedAccountEnvelope"}}}},"403":{"description":"Not the self-registered account credential"},"409":{"description":"Credential expired, changed concurrently, or replacement token already exists"}}}},"/credits/agent/catalog/search":{"post":{"tags":["Agent-native onboarding"],"summary":"Search capabilities for an agent-owned account","operationId":"postCreditsAgentCatalogSearch","description":"Searches the mutable catalog, including disabled capabilities, so a dashboardless agent can find exact provider/endpoint slugs before enabling them. System-managed virtual router endpoints are omitted because ordinary catalog controls cannot toggle them.","security":[{"agentConnection":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["query"],"properties":{"query":{"type":"string","minLength":1,"maxLength":256},"limit":{"type":"integer","minimum":1,"maximum":50}}}}}},"responses":{"200":{"description":"Ranked price-free capability metadata with current enablement"},"403":{"description":"Not the self-registered account credential"}}}},"/credits/agent/catalog":{"put":{"tags":["Agent-native onboarding"],"summary":"Enable or disable one agent-owned capability","operationId":"putCreditsAgentCatalog","description":"Changes only the enabled flag for one exact catalog slug on the self-registered account. It cannot change pricing or any other tenant setting.","security":[{"agentConnection":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["slug","enabled"],"properties":{"slug":{"type":"string","minLength":1,"maxLength":512},"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Effective capability enablement"},"403":{"description":"Not the self-registered account credential"},"404":{"description":"Unknown catalog slug"}}}},"/credits/agent/funding/config":{"get":{"tags":["Agent-native onboarding"],"summary":"Read agent funding constraints","operationId":"getCreditsAgentFundingConfig","description":"Returns exact top-up limits and confirms that Checkout is Stripe-hosted, the payer does not become owner, and no reusable payment method is delegated to the agent.","security":[{"agentConnection":[]}],"responses":{"200":{"description":"Funding constraints and Checkout properties"},"403":{"description":"Not the self-registered account credential"}}}},"/credits/agent/funding-sessions":{"post":{"tags":["Agent-native onboarding"],"summary":"Create a human funding handoff","operationId":"postCreditsAgentFundingSessions","description":"Creates an exact-amount, one-hour Stripe Checkout Session for the authenticated agent account. The payer card is not attached to the agent account for future use. Reuse the Idempotency-Key for retries of the same logical link.","security":[{"agentConnection":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentFundingAmount"}}}},"responses":{"201":{"description":"Stripe funding handoff created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentFundingSession"}}}},"400":{"description":"Invalid amount, missing Idempotency-Key, or code unclaimed_funding_limit: the account is unclaimed and would exceed $50 in total funding"},"403":{"description":"Funding is disabled for this account"},"429":{"description":"Funding-link rate limit exceeded"}}}},"/credits/agent/funding-sessions/{sessionId}":{"get":{"tags":["Agent-native onboarding"],"summary":"Poll an agent funding handoff","operationId":"getCreditsAgentFundingSessionsBySessionId","description":"Returns ready only after the signed Stripe webhook has been durably consumed and the credit ledger balance is usable.","security":[{"agentConnection":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","pattern":"^cs_"}}],"responses":{"200":{"description":"Current authenticated funding state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentFundingStatus"}}}},"404":{"description":"Session does not belong to this agent account"}}}},"/credits/agent/funding-sessions/public/{sessionId}":{"get":{"tags":["Agent-native onboarding"],"summary":"Read the payer-safe funding result","operationId":"getCreditsAgentFundingSessionsPublicBySessionId","description":"Public status used by the Stripe return page. The opaque Checkout Session ID is the capability. The response contains only state, agent display name, and credited amount; it never returns payer details or agent credentials.","security":[],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","pattern":"^cs_"}}],"responses":{"200":{"description":"Payer-safe funding state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentFundingPublicStatus"}}}},"404":{"description":"Unknown funding session"},"429":{"description":"Public polling rate limit exceeded"}}}},"/credits/.well-known/end-user-jwks.json":{"get":{"tags":["End users"],"summary":"Public JWKS for end-user tokens","operationId":"getCreditsWellKnownEndUserJwksJson","description":"RS256 public keys for verifying end-user tokens yourself, keyed by the token's kid claim. Public and cacheable for 5 minutes. Revoked signing keys are never published, so a token signed by a retired key fails verification here exactly as it does server-side.","security":[],"responses":{"200":{"description":"JWK Set","headers":{"Cache-Control":{"schema":{"const":"public, max-age=300, must-revalidate"}}},"content":{"application/json":{"schema":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"object","required":["kty","n","e","alg","use","kid"],"properties":{"kty":{"const":"RSA"},"n":{"type":"string"},"e":{"type":"string"},"alg":{"const":"RS256"},"use":{"const":"sig"},"kid":{"type":"string"}}}}}}}}}}}},"/credits/tenants/me/topups":{"get":{"tags":["Top-ups"],"summary":"List the account's payment history","operationId":"getCreditsTenantsMeTopups","description":"Returns only TOPUP ledger entries for the account's pooled balance, newest first. Available to Personal and enterprise accounts. Manual top-ups and automatic reloads are distinguished by entry metadata; this narrow history does not expose provider charges, end-user rows, or margin data.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":25,"default":25},"description":"Maximum entries to return."},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque nextCursor from the previous page."}],"responses":{"200":{"description":"Top-up history page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LedgerPage"}}}},"403":{"$ref":"#/components/responses/InsufficientScope"}}}},"/credits/tenants/me/topups/{entryId}/receipt":{"get":{"tags":["Top-ups"],"summary":"Open the Stripe receipt for one top-up","operationId":"getCreditsTenantsMeTopupsByEntryIdReceipt","description":"Returns Stripe's hosted receipt URL for one card top-up from the payment history. Only TOPUP entries on the account's pooled balance that came from a Stripe payment have one; anything else answers 404.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"entryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Ledger entry id from the payment history."}],"responses":{"200":{"description":"Receipt URL","content":{"application/json":{"schema":{"type":"object","required":["success","url"],"properties":{"success":{"type":"boolean","const":true},"url":{"type":"string","format":"uri"}}}}}},"403":{"$ref":"#/components/responses/InsufficientScope"},"404":{"description":"The entry has no card receipt."}}}},"/credits/tenants/me/spend-controls":{"get":{"tags":["Tenants"],"summary":"Read account spend and balance controls","operationId":"getCreditsTenantsMeSpendControls","description":"The account's monthly spend ceiling, spend-email threshold, low-balance threshold, and live position in the current UTC calendar-month window. Available to Personal and enterprise accounts. Read this before raising a limit: committedUsd, not spentUsd, is the figure enforced against the ceiling.","security":[{"dashboardSession":[]},{"secretKey":[]}],"responses":{"200":{"description":"Current controls and window position","content":{"application/json":{"schema":{"type":"object","required":["success","controls"],"properties":{"success":{"const":true},"controls":{"$ref":"#/components/schemas/WorkspaceSpendControls"}},"additionalProperties":false}}}},"403":{"$ref":"#/components/responses/InsufficientScope"}}},"put":{"tags":["Tenants"],"summary":"Set or clear account spend and balance controls","operationId":"putCreditsTenantsMeSpendControls","description":"Sets the monthly hard ceiling, monthly spend-email threshold, and/or low-balance email threshold. Send at least one field; omitted fields keep their current value and an explicit null clears one. Amounts are positive USD with at most 6 decimal places, up to 1000000000, and alertThresholdUsd may not exceed monthlyLimitUsd. Once committed spend reaches the ceiling, burns are denied with TENANT_MONTHLY_SPEND_LIMIT_EXCEEDED until the window resets — the limit bounds new spend and never cancels in-flight calls. Personal changes require the account owner on a session authenticated within the last ten minutes; enterprise changes require a workspace owner or admin with MFA or passkey step-up in that window.","security":[{"dashboardSession":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"properties":{"monthlyLimitUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}],"description":"Hard monthly ceiling, or null to remove it."},"alertThresholdUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}],"description":"Monthly spend email trigger, or null to remove it. Lowering it below current spend triggers the alert immediately."},"lowBalanceAlertUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}],"description":"Remaining prepaid-balance threshold for a one-time email, or null to remove it. The alert re-arms after the balance recovers above the threshold."}},"additionalProperties":false},"examples":{"setBoth":{"summary":"Cap at $5,000 and alert at $4,000","value":{"monthlyLimitUsd":"5000.00","alertThresholdUsd":"4000.00"}},"clearLimit":{"summary":"Remove the hard cap, keep the alerts","value":{"monthlyLimitUsd":null}},"setLowBalanceAlert":{"summary":"Email when the remaining balance reaches $10","value":{"lowBalanceAlertUsd":"10.00"}}}}}},"responses":{"200":{"description":"Updated controls","content":{"application/json":{"schema":{"type":"object","required":["success","controls"],"properties":{"success":{"const":true},"controls":{"$ref":"#/components/schemas/WorkspaceSpendControls"}},"additionalProperties":false}}}},"400":{"description":"Unknown field, no field supplied, a non-positive or over-precise amount, or an alert threshold above the limit."},"403":{"description":"RECENT_AUTHENTICATION_REQUIRED or OWNER_REQUIRED for a Personal account; STEP_UP_REQUIRED for an enterprise owner/admin without recent MFA/passkey step-up or for a non-workspace-administrator principal; or INSUFFICIENT_SCOPE."}}}},"/credits/tenants/me/keys/{keyId}":{"delete":{"tags":["Tenants"],"summary":"Revoke an API key","operationId":"deleteCreditsTenantsMeKeysByKeyId","description":"Revokes one key immediately; it returns 401 on the next request. Use this as the final step of a rotation, after the new credential is confirmed working. Requires a workspace owner or admin with MFA step-up completed in the last ten minutes.","security":[{"dashboardSession":[]}],"parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Key record id from GET /credits/tenants/me/keys."},{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Recorded on the credential audit event."}},"additionalProperties":false}}}},"responses":{"204":{"description":"Revoked. The key is dead as of this response. Idempotent: revoking an already-revoked key returns 204 again without a second audit event."},"400":{"description":"Invalid reason (over 200 characters, control characters, or not a string), or an unknown body field."},"403":{"description":"STEP_UP_REQUIRED or INSUFFICIENT_SCOPE."},"404":{"description":"No such key in this workspace (malformed ids included)."}}},"patch":{"tags":["Tenants"],"summary":"Rename an API key or change its tool set","operationId":"patchCreditsTenantsMeKeysByKeyId","description":"The secret itself never changes. Pass name, toolSetId, or both. toolSetId moves the key to that tool set (null moves it to Main); the next request with the same key uses the new set. Only secret keys take a tool set, and binding one narrows the key to the execution audience (moving back to Main keeps it narrowed). A rename alone appends a RENAMED credential audit event; a tool set change appends UPDATED with toolSetId and previousToolSetId. Requires a workspace owner or admin with MFA step-up completed in the last ten minutes.","security":[{"dashboardSession":[]}],"parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Key record id from GET /credits/tenants/me/keys."},{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"properties":{"name":{"type":"string","minLength":1,"maxLength":100},"toolSetId":{"type":["string","null"],"format":"uuid","description":"A tool set id from GET /credits/tool-sets, or null for Main."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Updated key metadata under keyMetadata."},"400":{"description":"Invalid name (empty, over 100 characters, or control characters), a tool set on a publishable or sandbox key, an empty body, an unknown body field, or the key is revoked."},"403":{"description":"STEP_UP_REQUIRED or INSUFFICIENT_SCOPE."},"404":{"description":"No such key, or no live tool set with that id, in this workspace (malformed ids included)."}}}},"/credits/tenants/me/keys/{keyId}/rotate":{"post":{"tags":["Tenants"],"summary":"Rotate ONE key; sibling keys of the same kind keep working","operationId":"postCreditsTenantsMeKeysByKeyIdRotate","description":"The replacement inherits the target's name, scopes, endpoint allowlist, pricing, audience (legacy policy-bearing rows are normalized to the execution audience), and — unless expiresIn is passed — its expiry deadline. A human caller cannot rotate a secret key whose inherited scopes include authority absent from their own effective membership scopes. Only the target is superseded: with gracePeriodSeconds > 0 it keeps authenticating until the overlap ends (capped at the target's own expiry), otherwise it is revoked with this response. Rotating a key that is already rotating out is rejected (rotate its replacement instead), as is rotating an expired key without a fresh expiresIn. This is the rotation the dashboard uses; the kind-level /keys/rotate remains the rotate-everything cutover. Requires a workspace owner or admin with MFA or passkey step-up completed in the last ten minutes.","security":[{"dashboardSession":[]}],"parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Key record id from GET /credits/tenants/me/keys."},{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"gracePeriodSeconds":{"type":"integer","minimum":0,"maximum":86400,"description":"Overlap during which the old key still works. Omitted or 0 means it dies with this response."},"expiresIn":{"type":"integer","minimum":60,"maximum":31536000,"description":"Lifetime of the replacement in seconds. Omit to inherit the target's deadline."}},"additionalProperties":false}}}},"responses":{"200":{"description":"New raw key (returned exactly once) with keyMetadata."},"400":{"description":"Target is revoked, already rotating out, expired without a fresh expiresIn, carries a secret scope the acting member does not hold — or an unknown body field."},"403":{"description":"STEP_UP_REQUIRED or INSUFFICIENT_SCOPE."},"404":{"description":"No such key in this workspace (malformed ids included)."}}}},"/credits/tenants/me/credentials/audit":{"get":{"tags":["Tenants"],"summary":"Credential lifecycle audit","operationId":"getCreditsTenantsMeCredentialsAudit","description":"Issue, rotate, and revoke events for API keys, agent connections, end-user tokens, and webhook secrets, newest first. Raw credentials and key hashes are never returned.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":100},"description":"Clamped to 1-200."}],"responses":{"200":{"description":"Credential audit events","content":{"application/json":{"schema":{"type":"object","required":["success","events"],"properties":{"success":{"const":true},"events":{"type":"array","items":{"$ref":"#/components/schemas/CredentialAuditEvent"}}},"additionalProperties":false}}}},"403":{"$ref":"#/components/responses/InsufficientScope"}}}},"/credits/tenants/me/security/audit":{"get":{"tags":["Tenants"],"summary":"Sensitive-mutation security audit","operationId":"getCreditsTenantsMeSecurityAudit","description":"Append-only record of sensitive workspace mutations with actor, auth method, request id, source IP, outcome, and before/after state. Written before the success response, so a failed audit write fails the mutation. Newest first.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":100},"description":"Clamped to 1-200."}],"responses":{"200":{"description":"Security audit events","content":{"application/json":{"schema":{"type":"object","required":["success","events"],"properties":{"success":{"const":true},"events":{"type":"array","items":{"$ref":"#/components/schemas/SecurityAuditEvent"}}},"additionalProperties":false}}}},"403":{"$ref":"#/components/responses/InsufficientScope"}}}},"/credits/pricing/explain":{"get":{"tags":["Catalog"],"summary":"Explain one endpoint's price","operationId":"getCreditsPricingExplain","description":"Breaks one endpoint's price into base cost, percentage markup, flat markup, your margin, and the customer-visible effective price, and names which configuration level supplied each markup. Endpoints priced live per call return the honest variable shape with null money fields rather than a fabricated base.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"provider","in":"query","required":true,"schema":{"type":"string"},"description":"Provider id, for example tavily."},{"name":"endpoint","in":"query","required":true,"schema":{"type":"string"},"description":"Endpoint name within that provider, for example search."},{"name":"args","in":"query","schema":{"type":"string"},"description":"JSON-encoded call arguments, used to price metered endpoints. Malformed JSON returns 400; any other JSON value parses and is passed through to the cost function, which ignores what it cannot use."}],"responses":{"200":{"description":"Price breakdown","content":{"application/json":{"schema":{"type":"object","required":["success","explain"],"properties":{"success":{"const":true},"explain":{"$ref":"#/components/schemas/PricingExplain"}},"additionalProperties":false}}}},"400":{"description":"provider or endpoint missing, or args is not a JSON-encoded object."},"403":{"$ref":"#/components/responses/InsufficientScope"},"404":{"description":"Unknown provider or endpoint."}}}},"/credits/end-users/{externalUserId}/tokens":{"get":{"tags":["End users"],"summary":"List an end user's minted tokens","operationId":"getCreditsEndUsersByExternalUserIdTokens","description":"Token metadata for one end user, newest first, capped at 200 records. Use it to audit what is outstanding and to find the tokenId to revoke. The tokens themselves are returned only at mint time and are never recoverable.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"externalUserId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ExternalUserId"}}],"responses":{"200":{"description":"Token metadata","content":{"application/json":{"schema":{"type":"object","required":["success","tokens"],"properties":{"success":{"const":true},"tokens":{"type":"array","items":{"$ref":"#/components/schemas/EndUserTokenRecord"}}},"additionalProperties":false}}}},"403":{"$ref":"#/components/responses/InsufficientScope"}}}},"/credits/end-users/{externalUserId}/tokens/{tokenId}":{"delete":{"tags":["End users"],"summary":"Revoke an end-user token","operationId":"deleteCreditsEndUsersByExternalUserIdTokensByTokenId","description":"Revokes one outstanding end-user token by its durable jti. Revocation takes effect immediately on the next use, which is the only way to cut a leaked token short — bearer tokens are otherwise replayable until they expire.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"externalUserId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ExternalUserId"}},{"name":"tokenId","in":"path","required":true,"schema":{"type":"string"},"description":"Token record id from GET /credits/end-users/{externalUserId}/tokens."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Recorded on the credential audit event."}},"additionalProperties":false}}}},"responses":{"204":{"description":"Revoked."},"403":{"$ref":"#/components/responses/InsufficientScope"},"404":{"description":"No such token for this end user."}}}},"/credits/stripe/operations":{"get":{"tags":["Top-ups"],"summary":"Top-up and Stripe ingress health","operationId":"getCreditsStripeOperations","description":"Operational health for this workspace's card funding: signed-webhook inbox state and recent top-up activity. Use it to tell a stuck top-up apart from a delivery backlog.","security":[{"dashboardSession":[]},{"secretKey":[]}],"responses":{"200":{"description":"Inbox and activity status","content":{"application/json":{"schema":{"type":"object","required":["success","operations"],"properties":{"success":{"const":true},"operations":{"type":"object","required":["inbox","activity"],"properties":{"inbox":{"type":"object","additionalProperties":true,"description":"Signed Stripe webhook inbox state, including unprocessed and dead-lettered counts."},"activity":{"type":"object","additionalProperties":true,"description":"Recent top-up session and settlement activity for this workspace."}}}},"additionalProperties":false}}}},"403":{"$ref":"#/components/responses/InsufficientScope"}}}},"/credits/billing/commercial":{"get":{"tags":["Ledger"],"summary":"Commercial agreement and invoice history","operationId":"getCreditsBillingCommercial","description":"Read-only view of an activated enterprise agreement, the live estimate for the current period, and issued invoice history. Workspaces without a commercial agreement get the empty shape rather than an error.","security":[{"dashboardSession":[]},{"secretKey":[]}],"responses":{"200":{"description":"Commercial billing summary","content":{"application/json":{"schema":{"type":"object","required":["success","commercial"],"properties":{"success":{"const":true},"commercial":{"type":"object","additionalProperties":true,"description":"Agreement terms, current-period estimate, and invoice history."}},"additionalProperties":false}}}},"403":{"$ref":"#/components/responses/InsufficientScope"}}}},"/credits/connect/stripe/status":{"get":{"tags":["Ledger"],"summary":"Stripe Connect status for payouts","operationId":"getCreditsConnectStripeStatus","description":"Whether this workspace is linked to a Stripe account for margin payouts, and whether Stripe currently permits payouts on it. Check this before switching payoutMethod to stripe.","security":[{"dashboardSession":[]},{"secretKey":[]}],"responses":{"200":{"description":"Connect status","content":{"application/json":{"schema":{"type":"object","required":["success","status"],"properties":{"success":{"const":true},"status":{"$ref":"#/components/schemas/StripeConnectStatus"}},"additionalProperties":false}}}},"403":{"$ref":"#/components/responses/InsufficientScope"}}}},"/credits/connect/stripe/authorize":{"get":{"tags":["Ledger"],"summary":"Begin Stripe Connect onboarding","operationId":"getCreditsConnectStripeAuthorize","description":"Returns the Stripe consent URL to send a workspace owner or admin to. Dashboard-only: a tenant secret key cannot start this flow, and evaluation workspaces are refused until a commercial agreement is active. Requires an owner or admin with MFA step-up completed in the last ten minutes.","security":[{"dashboardSession":[]}],"parameters":[{"name":"returnTo","in":"query","schema":{"type":"string"},"description":"Absolute dashboard URL to return to after consent. Defaults to the billing page."},{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"responses":{"200":{"description":"Consent URL","content":{"application/json":{"schema":{"type":"object","required":["success","url"],"properties":{"success":{"const":true},"url":{"type":"string","format":"uri"}},"additionalProperties":false}}}},"403":{"description":"STEP_UP_REQUIRED, a non-Cognito principal, INSUFFICIENT_SCOPE, or payouts locked for an evaluation workspace."}}}},"/credits/connect/stripe/callback":{"get":{"tags":["Ledger"],"summary":"Stripe Connect OAuth redirect target","operationId":"getCreditsConnectStripeCallback","description":"Stripe redirects the browser here after consent. Authorization comes from the signed state parameter rather than an Authorization header, so this route is deliberately public — do not call it yourself. It always answers with a 302 back to the dashboard, carrying connected=1 on success or connect_error=<code> on failure or cancellation.","security":[],"parameters":[{"name":"code","in":"query","schema":{"type":"string"},"description":"Stripe authorization code."},{"name":"state","in":"query","schema":{"type":"string"},"description":"Signed state minted by the authorize step."},{"name":"error","in":"query","schema":{"type":"string"},"description":"Present when the workspace administrator cancelled consent."}],"responses":{"302":{"description":"Redirect to the dashboard with connected=1 or connect_error=<code>."}}}},"/credits/connect/stripe/disconnect":{"post":{"tags":["Ledger"],"summary":"Disconnect Stripe and revert to USDC payouts","operationId":"postCreditsConnectStripeDisconnect","description":"Unlinks the Stripe account and returns the workspace to USDC margin payouts. Dashboard-only, and requires a workspace owner or admin with MFA step-up completed in the last ten minutes.","security":[{"dashboardSession":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"responses":{"200":{"description":"Disconnected","content":{"application/json":{"schema":{"type":"object","required":["success"],"properties":{"success":{"const":true}},"additionalProperties":false}}}},"403":{"description":"STEP_UP_REQUIRED, a non-Cognito principal, or INSUFFICIENT_SCOPE."}}}},"/credits/auth/signup":{"post":{"tags":["Authentication"],"summary":"Start a self-serve Locus Pro account","operationId":"postCreditsAuthSignup","description":"Creates an unconfirmed Cognito identity and sends a 6-digit email code. It does not provision a workspace or grant credits. Passwords require 8–256 characters with uppercase, lowercase, and numeric characters.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email","maxLength":254},"password":{"type":"string","format":"password","minLength":8,"maxLength":256},"name":{"type":"string","minLength":1,"maxLength":100}},"additionalProperties":false}}}},"responses":{"201":{"description":"Verification code sent","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["email","userConfirmed"],"properties":{"email":{"type":"string","format":"email"},"userConfirmed":{"type":"boolean"}},"additionalProperties":false}},"additionalProperties":false}}}},"400":{"description":"Invalid email, name, or password"},"409":{"description":"The account already exists; sign in or reset its password"},"429":{"description":"Signup rate limit exceeded"}}}},"/credits/auth/signup/confirm":{"post":{"tags":["Authentication"],"summary":"Verify email and create the self-serve workspace","operationId":"postCreditsAuthSignupConfirm","description":"Confirms the email, proves knowledge of the chosen password, and atomically provisions one owner workspace tied to the Cognito subject. Replays return that same workspace. The workspace starts with exactly $0 and receives no free or promotional credits.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","code","password"],"properties":{"email":{"type":"string","format":"email","maxLength":254},"code":{"type":"string","pattern":"^[0-9]{6}$"},"password":{"type":"string","format":"password","minLength":8,"maxLength":256},"workspaceName":{"type":"string","minLength":1,"maxLength":160,"description":"Optional account name. Defaults to the part of the email before the @."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Replay returned the already-provisioned workspace"},"201":{"description":"Workspace created; returns dashboard tokens or an MFA challenge, plus tenantId"},"400":{"description":"Invalid or expired verification code or invalid fields"},"401":{"description":"The password does not match the confirmed identity"},"403":{"description":"Email is not verified"},"429":{"description":"Verification rate limit exceeded"}}}},"/credits/auth/signup/resend":{"post":{"tags":["Authentication"],"summary":"Resend a signup verification code","operationId":"postCreditsAuthSignupResend","description":"Always returns the same success shape for a syntactically valid email, whether or not an unconfirmed identity exists.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","maxLength":254}},"additionalProperties":false}}}},"responses":{"200":{"description":"Generic resend acknowledgement"},"400":{"description":"Invalid email"},"429":{"description":"Signup rate limit exceeded"}}}},"/credits/tenants/self-serve":{"post":{"tags":["Tenants"],"summary":"Resume interrupted self-serve workspace provisioning","operationId":"postCreditsTenantsSelfServe","description":"Recovery-only companion for a verified, authenticated Cognito identity. The token subject is the durable idempotency key: repeated calls return the same zero-credit workspace and cannot create another one.","security":[{"dashboardSession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"workspaceName":{"type":"string","minLength":1,"maxLength":160,"description":"Optional account name. Defaults to the part of the email before the @."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Existing workspace returned with alreadyProvisioned=true"},"201":{"description":"Workspace created"},"401":{"description":"Authentication required"},"403":{"description":"Token subject mismatch or email is not verified"}}}},"/credits/evaluation-invitations/validate":{"post":{"tags":["Tenants"],"summary":"Validate an evaluation invitation","operationId":"postCreditsEvaluationInvitationsValidate","description":"Returns only the company, masked email, expiry and safe invitation state. The raw token is never returned or logged.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["token"],"properties":{"token":{"type":"string","pattern":"^lpei_"}}}}}},"responses":{"200":{"description":"Safe masked preview"},"404":{"description":"Invalid, expired or revoked"}}}},"/credits/evaluation-invitations/accept":{"post":{"tags":["Tenants"],"summary":"Create an evaluation account from a private invitation","operationId":"postCreditsEvaluationInvitationsAccept","description":"Creates the exact invited Cognito identity and atomically provisions one evaluation tenant and exactly $25 promotional credit. Existing identities must authenticate instead; this token is never a password-reset credential.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["token","password"],"properties":{"token":{"type":"string","pattern":"^lpei_"},"name":{"type":"string","maxLength":100},"password":{"type":"string","minLength":8,"maxLength":256,"format":"password","writeOnly":true}}}}}},"responses":{"201":{"description":"Evaluation tenant provisioned"},"409":{"description":"Concurrent provisioning or existing account must sign in"}}}},"/credits/evaluation-invitations/accept-existing":{"post":{"tags":["Tenants"],"summary":"Accept an invitation as the matching signed-in identity","operationId":"postCreditsEvaluationInvitationsAcceptExisting","description":"The live Cognito email must exactly match the invited email. Successful acceptance selects the returned tenant with X-Locus-Tenant-Id.","security":[{"dashboardSession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["token"],"properties":{"token":{"type":"string","pattern":"^lpei_"}}}}}},"responses":{"200":{"description":"Evaluation tenant selected or provisioned"},"403":{"description":"Signed-in email does not match"}}}},"/credits/member-invitations/validate":{"post":{"tags":["Workspace members"],"summary":"Validate a workspace invitation","operationId":"postCreditsMemberInvitationsValidate","description":"Returns a masked-email preview for a single-use invitation token. The token is read from the email URL fragment and submitted in JSON so it does not enter normal access logs or referrers.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["token"],"properties":{"token":{"type":"string","pattern":"^lpmi_","maxLength":128}}}}}},"responses":{"200":{"description":"Safe invitation preview","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["invitation"],"properties":{"invitation":{"$ref":"#/components/schemas/WorkspaceInvitationPreview"}}}}}}}},"404":{"description":"Invitation is invalid, expired, revoked, or already consumed"}}}},"/credits/member-invitations/accept":{"post":{"tags":["Workspace members"],"summary":"Create the invited identity and join its workspace","operationId":"postCreditsMemberInvitationsAccept","description":"Creates an account only for the exact invited email and joins the existing workspace. This is not a public account-creation surface. Existing identities must use the authenticated acceptance route.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["token","name","password"],"properties":{"token":{"type":"string","pattern":"^lpmi_","maxLength":128},"name":{"type":"string","minLength":1,"maxLength":100},"password":{"type":"string","minLength":8,"maxLength":256,"format":"password","writeOnly":true}}}}}},"responses":{"201":{"description":"Account created and workspace membership activated"},"409":{"description":"Existing identity must sign in, or provisioning is already active"}}}},"/credits/member-invitations/accept-existing":{"post":{"tags":["Workspace members"],"summary":"Join a workspace as the matching signed-in identity","operationId":"postCreditsMemberInvitationsAcceptExisting","description":"The live Cognito email must exactly match the invited email. The response identifies the workspace to select with X-Locus-Tenant-Id.","security":[{"dashboardSession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["token"],"properties":{"token":{"type":"string","pattern":"^lpmi_","maxLength":128}}}}}},"responses":{"200":{"description":"Previously completed invitation selected idempotently"},"201":{"description":"Workspace membership activated"},"403":{"description":"Signed-in email does not match the invitation"},"409":{"description":"Invitation is invalid, expired, already in progress for another identity, or the signed-in identity is already a member"}}}},"/credits/tenants":{"get":{"tags":["Workspace members"],"summary":"List the signed-in person's workspace memberships","operationId":"getCreditsTenants","description":"This discovery route does not require X-Locus-Tenant-Id. Use the selected tenantId as that header on subsequent dashboard management calls when the person belongs to multiple workspaces.","security":[{"dashboardSession":[]}],"responses":{"200":{"description":"Memberships visible to the signed-in identity","content":{"application/json":{"schema":{"type":"object","required":["success","memberships"],"properties":{"success":{"const":true},"memberships":{"type":"array","items":{"$ref":"#/components/schemas/WorkspaceMembership"}}}}}}}}}},"/credits/members":{"get":{"tags":["Workspace members"],"summary":"List workspace members and pending invitations","operationId":"getCreditsMembers","description":"Human Cognito sessions only. Tenant API keys cannot enumerate workspace member email addresses.","security":[{"dashboardSession":[]}],"responses":{"200":{"description":"Workspace members and active invitations","content":{"application/json":{"schema":{"type":"object","required":["success","members","invitations"],"properties":{"success":{"const":true},"members":{"type":"array","items":{"$ref":"#/components/schemas/WorkspaceMember"}},"invitations":{"type":"array","items":{"$ref":"#/components/schemas/WorkspaceInvitation"}}}}}}},"403":{"description":"A non-human credential attempted to enumerate workspace membership"}}}},"/credits/member-invitations":{"post":{"tags":["Workspace members"],"summary":"Invite people to a workspace","operationId":"postCreditsMemberInvitations","description":"Requires owner or admin membership, members:manage, and MFA or passkey step-up within the last ten minutes. Accepts at most 20 unique normalized email addresses.","security":[{"dashboardSession":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["emails","role"],"properties":{"emails":{"type":"array","minItems":1,"maxItems":20,"uniqueItems":true,"items":{"type":"string","format":"email","maxLength":254}},"role":{"$ref":"#/components/schemas/InvitableWorkspaceRole"}}}}}},"responses":{"201":{"description":"Invitation records persisted and immediate delivery attempted"},"403":{"description":"Missing owner/admin role, scope, or recent step-up"}}}},"/credits/member-invitations/{invitationId}/resend":{"post":{"tags":["Workspace members"],"summary":"Rotate and resend a pending workspace invitation","operationId":"postCreditsMemberInvitationsByInvitationIdResend","description":"Requires owner or admin membership, members:manage, and recent MFA or passkey step-up. Rotating the token invalidates the previous email link.","security":[{"dashboardSession":[]}],"parameters":[{"name":"invitationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"responses":{"200":{"description":"Invitation token rotated and delivery attempted"},"403":{"description":"Missing authorization or step-up"},"404":{"description":"Invitation not found"}}}},"/credits/member-invitations/{invitationId}":{"delete":{"tags":["Workspace members"],"summary":"Revoke a workspace invitation","operationId":"deleteCreditsMemberInvitationsByInvitationId","description":"Requires owner or admin membership, members:manage, and recent MFA or passkey step-up.","security":[{"dashboardSession":[]}],"parameters":[{"name":"invitationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"responses":{"204":{"description":"Invitation revoked"},"403":{"description":"Missing authorization or step-up"},"404":{"description":"Invitation not found"}}}},"/credits/members/{memberId}":{"patch":{"tags":["Workspace members"],"summary":"Change a workspace member role","operationId":"patchCreditsMembersByMemberId","description":"Requires owner or admin membership, members:manage, and recent MFA or passkey step-up. The owner's role cannot be changed here (use the transfer-ownership operation) and a member cannot change their own role.","security":[{"dashboardSession":[]}],"parameters":[{"name":"memberId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["role"],"properties":{"role":{"$ref":"#/components/schemas/InvitableWorkspaceRole"}}}}}},"responses":{"200":{"description":"Role updated"},"403":{"description":"Missing authorization or step-up"},"404":{"description":"Member not found"},"409":{"description":"The owner cannot be reassigned here, or the acting member tried to change their own role, or the member changed (for example became the owner) before this request completed"}}},"delete":{"tags":["Workspace members"],"summary":"Remove a workspace member","operationId":"deleteCreditsMembersByMemberId","description":"Requires owner or admin membership, members:manage, and recent MFA or passkey step-up. The current owner cannot be removed and a member cannot remove their own current membership.","security":[{"dashboardSession":[]}],"parameters":[{"name":"memberId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"responses":{"204":{"description":"Member removed"},"403":{"description":"Missing authorization or step-up"},"404":{"description":"Member not found"},"409":{"description":"The current owner or acting member cannot be removed, or the member changed (for example became the owner) before this request completed"}}}},"/credits/members/{memberId}/transfer-ownership":{"post":{"tags":["Workspace members"],"summary":"Transfer workspace ownership","operationId":"postCreditsMembersByMemberIdTransferOwnership","description":"Requires the current owner's dashboard session, members:manage, and recent MFA or passkey step-up. Admins and secret keys are refused. The target becomes the owner and the acting owner becomes an admin; only the new owner can transfer ownership again.","security":[{"dashboardSession":[]}],"parameters":[{"name":"memberId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"responses":{"200":{"description":"Ownership transferred; returns the new owner membership","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["success","member"],"properties":{"success":{"const":true},"member":{"$ref":"#/components/schemas/WorkspaceMember"}}}}}},"403":{"description":"Caller is not the owner, lacks members:manage, or has no recent step-up"},"404":{"description":"Member not found in this workspace"},"409":{"description":"The acting member is not the owner, already owns the workspace, or ownership moved concurrently"}}}},"/credits/auth/credential":{"get":{"tags":["Authentication"],"summary":"Inspect the current management credential","operationId":"getCreditsAuthCredential","description":"Returns only the authenticated credential kind, tenant, role, effective scopes, and current step-up state. Owner and admin dashboard sessions are step-up eligible; developer, billing, viewer, and secret-key principals are not. It never returns raw keys, hashes, JWT claims, or secrets. Call this before attempting a scoped management operation.","security":[{"dashboardSession":[]},{"secretKey":[]}],"responses":{"200":{"description":"Effective authorization context","content":{"application/json":{"schema":{"type":"object","required":["success","credential"],"properties":{"success":{"const":true},"credential":{"type":"object","required":["auth","tenantId","role","credentialId","scopes","stepUpEligible","stepUpFresh"],"properties":{"auth":{"type":"string","enum":["secret_key","cognito"]},"tenantId":{"type":"string","format":"uuid"},"role":{"oneOf":[{"$ref":"#/components/schemas/WorkspaceRole"},{"type":"null"}]},"credentialId":{"type":["string","null"]},"scopes":{"type":"array","uniqueItems":true,"items":{"$ref":"#/components/schemas/CreditsTenantScope"}},"stepUpEligible":{"type":"boolean"},"stepUpFresh":{"type":"boolean"}},"additionalProperties":false}},"additionalProperties":false}}}},"401":{"description":"Missing, invalid, expired, or revoked management credential"}}}},"/credits/agent-connections":{"post":{"tags":["Authentication","MCP"],"summary":"Create a scoped Agent Connection","operationId":"postCreditsAgentConnections","description":"Creates a short-lived, least-privilege lcac_ credential for MCP and wrapped execution. Because the returned credential can spend credits, callers must hold both credentials:manage and credits:move rather than delegating spend authority they do not hold. A secret key with both scopes may automate this route; human callers must be a workspace owner or admin with fresh MFA/passkey step-up.","security":[{"dashboardSession":[]},{"secretKey":[]}],"x-required-scopes":["credentials:manage","credits:move"],"parameters":[{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConnectionCreateRequest"}}}},"responses":{"201":{"description":"Connection created; credential is returned once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConnectionEnvelope"}}}},"400":{"description":"Invalid identity, endpoint, expiry, or exact-credit scope"},"401":{"$ref":"#/components/responses/UnauthorizedManagement"},"403":{"$ref":"#/components/responses/InsufficientScope"}}},"get":{"tags":["Authentication","MCP"],"summary":"List scoped Agent Connections","operationId":"getCreditsAgentConnections","security":[{"dashboardSession":[]},{"secretKey":[]}],"x-required-scopes":["credentials:manage"],"responses":{"200":{"description":"Connection metadata; raw credentials are never returned","content":{"application/json":{"schema":{"type":"object","required":["success","connections"],"properties":{"success":{"const":true},"connections":{"type":"array","items":{"$ref":"#/components/schemas/AgentConnection"}},"nextCursor":{"type":["string","null"]}},"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/UnauthorizedManagement"},"403":{"$ref":"#/components/responses/InsufficientScope"}},"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Pass nextCursor from the previous page unchanged."},{"name":"externalUserId","in":"query","schema":{"type":"string"},"description":"Only connections bound to this customer."}],"description":"Results are bounded to 100 records and sorted newest first. Follow nextCursor until null."}},"/credits/agent-connections/{connectionId}":{"get":{"tags":["Authentication","MCP"],"summary":"Read one scoped Agent Connection","operationId":"getCreditsAgentConnectionsByConnectionId","description":"Returns the metadata of one Agent Connection in the caller workspace, such as its allowed tools, limits, and expiry. The raw lcac_ credential is never returned. Returns 404 when the connection belongs to another workspace.","security":[{"dashboardSession":[]},{"secretKey":[]}],"x-required-scopes":["credentials:manage"],"parameters":[{"$ref":"#/components/parameters/AgentConnectionId"}],"responses":{"200":{"description":"Connection metadata; the raw credential is omitted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConnectionEnvelope"}}}},"401":{"$ref":"#/components/responses/UnauthorizedManagement"},"403":{"$ref":"#/components/responses/InsufficientScope"},"404":{"description":"Connection not found in this workspace"}}},"patch":{"tags":["Authentication","MCP"],"summary":"Change a scoped Agent Connection's tool set","operationId":"patchCreditsAgentConnectionsByConnectionId","description":"Moves the credential to another tool set (null moves it to Main). The lcac_ value does not change and the next call uses the new set. A credential that still carries a hand-picked tool list can only move to a list that has every one of those tools on. Callers require credentials:manage and credits:move; a scoped secret key with both may automate this operation, while human callers additionally require owner/admin step-up.","security":[{"dashboardSession":[]},{"secretKey":[]}],"x-required-scopes":["credentials:manage","credits:move"],"parameters":[{"$ref":"#/components/parameters/AgentConnectionId"},{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["toolSetId"],"properties":{"toolSetId":{"type":["string","null"],"format":"uuid","description":"A tool set id from GET /credits/tool-sets, or null for Main."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Connection metadata with the new toolSetId; the raw credential is omitted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConnectionEnvelope"}}}},"400":{"description":"Missing toolSetId, an unknown field, no live tool set with that id, or the credential's tools are off in the target list"},"401":{"$ref":"#/components/responses/UnauthorizedManagement"},"403":{"$ref":"#/components/responses/InsufficientScope"},"404":{"description":"Connection not found in this workspace"},"409":{"description":"Connection is no longer active"}}}},"/credits/agent-connections/{connectionId}/rotate":{"post":{"tags":["Authentication","MCP"],"summary":"Rotate a scoped Agent Connection credential","operationId":"postCreditsAgentConnectionsByConnectionIdRotate","description":"Immediately invalidates the prior lcac_ credential and returns its spend-capable replacement once. Callers require credentials:manage and credits:move; a scoped secret key with both may automate this operation, while human callers additionally require owner/admin step-up.","security":[{"dashboardSession":[]},{"secretKey":[]}],"x-required-scopes":["credentials:manage","credits:move"],"parameters":[{"$ref":"#/components/parameters/AgentConnectionId"},{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"responses":{"200":{"description":"Credential rotated and returned once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConnectionEnvelope"}}}},"401":{"$ref":"#/components/responses/UnauthorizedManagement"},"403":{"$ref":"#/components/responses/InsufficientScope"},"404":{"description":"Connection not found in this workspace"},"409":{"description":"Connection is no longer active"}}}},"/credits/agent-connections/{connectionId}/revoke":{"post":{"tags":["Authentication","MCP"],"summary":"Revoke a scoped Agent Connection credential","operationId":"postCreditsAgentConnectionsByConnectionIdRevoke","description":"Idempotently revokes the lcac_ credential. A scoped secret key may automate this Agent Connection operation; human callers require owner/admin step-up.","security":[{"dashboardSession":[]},{"secretKey":[]}],"x-required-scopes":["credentials:manage"],"parameters":[{"$ref":"#/components/parameters/AgentConnectionId"},{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"responses":{"200":{"description":"Connection is revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConnectionEnvelope"}}}},"401":{"$ref":"#/components/responses/UnauthorizedManagement"},"403":{"$ref":"#/components/responses/InsufficientScope"},"404":{"description":"Connection not found in this workspace"}}}},"/credits/tenants/me":{"get":{"tags":["Tenants"],"summary":"Get tenant profile","operationId":"getCreditsTenantsMe","description":"Returns the calling workspace's profile and configuration. Use it to confirm which workspace a credential or dashboard session acts on before making changes.","security":[{"dashboardSession":[]},{"secretKey":[]}],"responses":{"200":{"description":"Tenant profile and configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tenant"}}}}}},"patch":{"tags":["Tenants"],"summary":"Update tenant profile","operationId":"patchCreditsTenantsMe","description":"Workspace owner/admin session or a secret key with tenant:write. Unknown fields are rejected atomically; recognized fields are never applied from a mixed known/unknown request. creditsPerDollar is immutable after provisioning and is rejected if supplied.","security":[{"dashboardSession":[]},{"secretKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"defaultMarkupBps":{"type":"integer","minimum":0,"maximum":10000},"feeMode":{"type":"string","enum":["pass_through","absorb"]},"billingMode":{"type":"string","enum":["wholesale_pool","embedded_topups"]}},"additionalProperties":false}}}},"responses":{"200":{"description":"Tenant profile updated"},"400":{"description":"Invalid profile value, immutable creditsPerDollar, or one or more unknown fields","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/UnknownTenantFieldsError"},{"type":"object","required":["success","error","message"],"properties":{"success":{"const":false},"error":{"const":"Bad Request"},"message":{"type":"string"}}}]}}}},"403":{"description":"Caller is neither an owner/admin dashboard member nor a secret key, or lacks tenant:write"}}},"put":{"tags":["Tenants"],"summary":"Update tenant settings","operationId":"putCreditsTenantsMe","description":"Workspace owner/admin sessions and secret keys with tenant:write may update webhookUrl or feeMode. A new webhookUrl is queued for an isolated ownership challenge; the previously verified URL remains active until that challenge succeeds. Requests containing marginPayoutAddress or payoutMethod require a dashboard session from a workspace owner or admin with MFA or passkey step-up completed in the last ten minutes; every other principal receives 403. Changing marginPayoutAddress starts a 24-hour payout hold.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"webhookUrl":{"type":["string","null"],"format":"uri"},"feeMode":{"type":"string","enum":["pass_through","absorb"]},"marginPayoutAddress":{"type":["string","null"],"pattern":"^0x[a-fA-F0-9]{40}$","description":"Dashboard-session only. A change starts a 24-hour payout hold."},"payoutMethod":{"type":"string","enum":["usdc","stripe"],"description":"Dashboard-session only."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Settings updated; no webhook ownership challenge is pending"},"202":{"description":"Settings updated and webhook ownership verification queued","content":{"application/json":{"schema":{"type":"object","required":["success","tenant","webhookVerification"],"properties":{"success":{"const":true},"tenant":{"$ref":"#/components/schemas/Tenant"},"webhookVerification":{"$ref":"#/components/schemas/WebhookVerification"}}}}}},"400":{"description":"Invalid setting or one or more unknown fields","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/UnknownTenantFieldsError"},{"type":"object","required":["success","error","message"],"properties":{"success":{"const":false},"error":{"const":"Bad Request"},"message":{"type":"string"}}}]}}}},"403":{"description":"INSUFFICIENT_SCOPE, STEP_UP_REQUIRED for a payout-setting change, a secret key attempted a dashboard-only payout change, or payouts are locked for an evaluation workspace"}}}},"/credits/tenants/me/keys":{"get":{"tags":["Tenants"],"summary":"List API-key metadata and immutable execution policies","operationId":"getCreditsTenantsMeKeys","description":"Raw keys and hashes are never returned; every caller sees lifecycle metadata including createdBy (issuer subject). Dashboard (Cognito) sessions additionally receive createdByEmail (workspace member email when the issuer is still a member) and usage (current-UTC-month burn attribution: monthUsdc, monthCalls — null for keys with no attributed burns; attribution began 2026-08 with the burn initiator envelope). Secret-key callers never receive those two enrichment fields: member emails and spend rollups stay behind a human session, matching the /members boundary. Results are bounded to 100 records and sorted newest first. Follow nextCursor until null.","security":[{"dashboardSession":[]},{"secretKey":[]}],"responses":{"200":{"description":"{ success, keys: [...] } — lifecycle metadata only; raw keys and hashes are never returned"},"403":{"description":"INSUFFICIENT_SCOPE (needs credentials:manage; dashboard callers must be owner or admin)."}},"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Pass nextCursor from the previous page unchanged."},{"name":"usage","in":"query","schema":{"type":"boolean","default":true},"description":"Set to false to omit the dashboard-session enrichment (usage and createdByEmail). Paging a large key list for a picker does not need the month's usage rollup on every page."}]},"post":{"tags":["Tenants"],"summary":"Issue an independently scoped API key","operationId":"postCreditsTenantsMeKeys","description":"Creates an overlapping named credential. Requires a workspace owner or admin with credentials:manage and MFA or passkey step-up completed in the last ten minutes. A human caller cannot put a scope on a secret key that is absent from their own effective membership scopes. tools.enable narrows the tenant-enabled catalog for this key; pricing applies only to end-user calls and never widens tenant enablement. kind 'sandbox' issues a scopeless test credential (lcrsb_...) whose metered calls are simulated: no credits move and no providers are called. Unknown body fields are rejected with 400.","security":[{"dashboardSession":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreateRequest"}}}},"responses":{"201":{"description":"{ success, kind, key, keyMetadata } — the raw key is returned exactly once, with the stored lifecycle metadata beside it."},"400":{"description":"Invalid kind, name, scopes (including a secret scope the acting member does not hold), tools, pricing, expiresIn — or an unknown body field."},"403":{"description":"STEP_UP_REQUIRED or INSUFFICIENT_SCOPE."}}}},"/credits/tenants/me/keys/rotate":{"post":{"tags":["Tenants"],"summary":"Rotate every active key of a kind (cutover)","operationId":"postCreditsTenantsMeKeysRotate","description":"Creates ONE replacement and supersedes ALL other active keys of that kind. Requires a workspace owner or admin with credentials:manage and MFA or passkey step-up completed in the last ten minutes. A human caller cannot delegate a secret-key scope absent from their own effective membership scopes. For rotating a single key while its siblings keep working, use POST /credits/tenants/me/keys/{keyId}/rotate.","security":[{"dashboardSession":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["secret","publishable","sandbox"]},"expiresIn":{"type":["integer","null"],"description":"Lifetime of the new key in seconds. Omit for the default."},"scopes":{"type":"array","items":{"$ref":"#/components/schemas/CreditsTenantScope"},"description":"Scopes for the new key. Omit to keep the kind's defaults. Publishable keys accept only widget:read."},"name":{"type":"string","minLength":1,"maxLength":100,"description":"Name for the replacement key."},"tools":{"type":"object","additionalProperties":false,"required":["enable"],"properties":{"enable":{"type":"array","maxItems":1000,"items":{"type":"string","pattern":"^[^/]+/[^/]+$"},"uniqueItems":true}},"description":"Endpoint allowlist for the replacement; makes it a burn-only execution credential."},"pricing":{"$ref":"#/components/schemas/CredentialPricingPolicy"},"gracePeriodSeconds":{"type":"integer","minimum":0,"description":"Keep the old key valid this long for zero-downtime cutover. Omitted means the old key dies with this response."}},"additionalProperties":false}}}},"responses":{"200":{"description":"{ success, kind, key, keyPrefix } — the raw key is returned exactly once. Unlike create and per-key rotation, this cutover endpoint returns keyPrefix rather than a keyMetadata object. Without gracePeriodSeconds the superseded keys stop working with this response; with it they keep authenticating until the overlap ends."},"400":{"description":"Invalid field or unknown body field — including a requested secret scope the acting member does not hold, or a bare rotation that would silently widen authority (some active key of the kind carries an endpoint allowlist, pricing, execution audience, or narrowed scopes; pass the replacement's shape explicitly)."},"403":{"description":"STEP_UP_REQUIRED or INSUFFICIENT_SCOPE."},"409":{"description":"TOOL_SET_BOUND_KEYS: an active key of this kind is bound to a tool set, and one replacement on Main would move its traffic off that set. Refused whatever scopes, tools, or pricing are passed; rotate those keys with POST /credits/tenants/me/keys/{keyId}/rotate, which keeps the set."}}}},"/credits/tenants/me/webhook-verification":{"get":{"tags":["Webhooks"],"summary":"Read the latest webhook ownership challenge","operationId":"getCreditsTenantsMeWebhookVerification","description":"Polling this endpoint never reveals or consumes the webhook signing secret.","security":[{"dashboardSession":[]},{"secretKey":[]}],"responses":{"200":{"description":"Latest tenant-scoped verification, or null when none was requested","content":{"application/json":{"schema":{"type":"object","required":["success","webhookVerification"],"properties":{"success":{"const":true},"webhookVerification":{"oneOf":[{"$ref":"#/components/schemas/WebhookVerification"},{"type":"null"}]}}}}}}}}},"/credits/tenants/me/webhook-secret/reveal":{"post":{"tags":["Webhooks"],"summary":"Reveal the first verified webhook signing secret once","operationId":"postCreditsTenantsMeWebhookSecretReveal","description":"Workspace owner/admin and MFA/passkey step-up protected. Status polling cannot consume this reveal. If it was already revealed, rotate the secret instead.","security":[{"dashboardSession":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"responses":{"200":{"description":"First signing secret","content":{"application/json":{"schema":{"type":"object","required":["success","webhookSecret"],"properties":{"success":{"const":true},"webhookSecret":{"type":"string","pattern":"^whsec_"}}}}}},"409":{"description":"Verification is incomplete or the secret was already revealed"}}}},"/credits/tenants/me/webhook-secret/rotate":{"post":{"tags":["Webhooks"],"summary":"Rotate the webhook signing secret","operationId":"postCreditsTenantsMeWebhookSecretRotate","description":"Returns the new secret once. Requires a workspace owner or admin with credentials:manage and MFA or passkey step-up completed in the last ten minutes. Deliveries contain signatures for both the current and previous secrets during a 24-hour overlap.","security":[{"dashboardSession":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"responses":{"200":{"description":"New signing secret and old-secret expiry","content":{"application/json":{"schema":{"type":"object","required":["success","webhook_secret","previous_secret_valid_until"],"properties":{"success":{"const":true},"webhook_secret":{"type":"string","pattern":"^whsec_"},"previous_secret_valid_until":{"type":"string","format":"date-time"}}}}}}}}},"/credits/tenants/me/auto-recharge":{"post":{"tags":["Top-ups"],"summary":"Configure automatic balance reload","operationId":"postCreditsTenantsMeAutoRecharge","description":"Charges the saved card when the account's prepaid balance falls below thresholdUsd and credits amountUsd. Both fields must be positive and supplied together; send both as null to disable. Personal accounts call this auto-reload and require the account owner on a session authenticated within the last ten minutes. Enterprise workspaces call it auto-recharge and require a workspace owner or admin with payouts:manage plus recent MFA or passkey step-up. Evaluation workspaces may configure auto-recharge without activating a commercial agreement. Make one successful manual top-up first so Stripe has a reusable payment method.","security":[{"dashboardSession":[]}],"parameters":[{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["thresholdUsd","amountUsd"],"properties":{"thresholdUsd":{"$ref":"#/components/schemas/DecimalString"},"amountUsd":{"$ref":"#/components/schemas/DecimalString"}},"additionalProperties":false},{"type":"object","required":["thresholdUsd","amountUsd"],"properties":{"thresholdUsd":{"type":"null"},"amountUsd":{"type":"null"}},"additionalProperties":false}]}}}},"responses":{"200":{"description":"Automatic reload configuration updated; autoRecharge is null when disabled"},"400":{"description":"Unknown field, non-positive amount, or only one of thresholdUsd and amountUsd was supplied"},"403":{"description":"Owner/recent-authentication requirement, enterprise step-up requirement, insufficient scope, or funding unavailable"}}}},"/credits/custom-endpoints":{"get":{"tags":["Custom APIs"],"summary":"List custom API providers and actions","operationId":"getCreditsCustomEndpoints","description":"Feature-gated enterprise management surface. Requires catalog:write. The raw upstream credential is never returned. Only a workspace owner whose credential also has credentials:manage receives the provider base URL and redacted authentication metadata; every other authorized caller receives null for those upstream configuration fields.","security":[{"dashboardSession":[]},{"secretKey":[]}],"x-required-scopes":["catalog:write"],"responses":{"200":{"description":"Custom providers, effective workspace markup cap, and schema-backed actions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomProviderListResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedManagement"},"403":{"description":"Custom APIs are not enabled for this enterprise workspace or the credential lacks catalog:write"}}},"post":{"tags":["Custom APIs"],"summary":"Create a custom API provider","operationId":"postCreditsCustomEndpoints","description":"Creates one BYOK provider and optionally up to 50 actions atomically. Requires an enterprise workspace with Custom APIs enabled, the workspace owner, credentials:manage and catalog:write, plus MFA or passkey step-up completed in the last ten minutes. Locus validates the upstream URL against SSRF controls, encrypts the credential, validates every JSON Schema and example, and never returns the raw credential.","security":[{"dashboardSession":[]}],"x-required-scopes":["credentials:manage","catalog:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomProviderCreateRequest"}}}},"responses":{"201":{"description":"Provider and any supplied actions created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomProviderResponse"}}}},"400":{"description":"Invalid URL, authentication, traffic policy, schema, example, route, or pricing"},"403":{"description":"Feature, enterprise plan, owner, scope, or recent step-up requirement not met"},"409":{"description":"That provider slug is already in use in this workspace"}}}},"/credits/custom-endpoints/{providerId}":{"patch":{"tags":["Custom APIs"],"summary":"Update a custom API provider","operationId":"patchCreditsCustomEndpointsByProviderId","description":"Updates provider presentation, SSRF-checked base URL, authentication, or traffic protection. Supplying a new credential rotates the encrypted secret; type=none removes it. Requires the same enterprise owner, scope, and recent step-up controls as creation.","security":[{"dashboardSession":[]}],"x-required-scopes":["credentials:manage","catalog:write"],"parameters":[{"$ref":"#/components/parameters/CustomProviderId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomProviderUpdateRequest"}}}},"responses":{"200":{"description":"Provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomProviderResponse"}}}},"400":{"description":"No changes or invalid configuration"},"403":{"description":"Feature, enterprise plan, owner, scope, or recent step-up requirement not met"},"404":{"description":"Custom provider not found in this workspace"}}},"delete":{"tags":["Custom APIs"],"summary":"Delete a custom API provider","operationId":"deleteCreditsCustomEndpointsByProviderId","description":"Permanently removes the provider, its encrypted upstream credential, and its custom actions. Requires the same enterprise owner, scope, and recent step-up controls as creation.","security":[{"dashboardSession":[]}],"x-required-scopes":["credentials:manage","catalog:write"],"parameters":[{"$ref":"#/components/parameters/CustomProviderId"}],"responses":{"204":{"description":"Provider and actions deleted"},"403":{"description":"Feature, enterprise plan, owner, scope, or recent step-up requirement not met"},"404":{"description":"Custom provider not found in this workspace"}}}},"/credits/custom-endpoints/{providerId}/endpoints":{"post":{"tags":["Custom APIs"],"summary":"Create an action for a custom provider","operationId":"postCreditsCustomEndpointsByProviderIdEndpoints","description":"Creates one disabled-by-default or explicitly enabled action. Its input schema must describe an object, its example must validate, path placeholders must resolve to scalar schema properties, and the top-level names externalUserId, attribution, and _locus are reserved for Locus transport controls. Publishing an enabled action requires a positive end-user price.","security":[{"dashboardSession":[]}],"x-required-scopes":["credentials:manage","catalog:write"],"parameters":[{"$ref":"#/components/parameters/CustomProviderId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomEndpointCreateRequest"}}}},"responses":{"201":{"description":"Action created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomEndpointResponse"}}}},"400":{"description":"Invalid schema, example, path, pricing, or action configuration"},"403":{"description":"Feature, enterprise plan, owner, scope, or recent step-up requirement not met"},"404":{"description":"Custom provider not found in this workspace"},"409":{"description":"That action slug is already in use for this provider"}}}},"/credits/custom-endpoints/{providerId}/endpoints/{endpointId}":{"patch":{"tags":["Custom APIs"],"summary":"Update a custom API action","operationId":"patchCreditsCustomEndpointsByProviderIdEndpointsByEndpointId","description":"Updates one action without changing its stable slug. Contract and pricing changes are revalidated; a pricing change increments pricingRevision. Requires the enterprise owner with credentials:manage, catalog:write, and recent step-up.","security":[{"dashboardSession":[]}],"x-required-scopes":["credentials:manage","catalog:write"],"parameters":[{"$ref":"#/components/parameters/CustomProviderId"},{"$ref":"#/components/parameters/CustomEndpointId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomEndpointUpdateRequest"}}}},"responses":{"200":{"description":"Action updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomEndpointResponse"}}}},"400":{"description":"No changes or invalid schema, example, path, pricing, or action configuration"},"403":{"description":"Feature, enterprise plan, owner, scope, or recent step-up requirement not met"},"404":{"description":"Custom provider or action not found in this workspace"}}},"delete":{"tags":["Custom APIs"],"summary":"Delete a custom API action","operationId":"deleteCreditsCustomEndpointsByProviderIdEndpointsByEndpointId","description":"Permanently removes one custom action. Requires the enterprise owner with credentials:manage, catalog:write, and recent step-up.","security":[{"dashboardSession":[]}],"x-required-scopes":["credentials:manage","catalog:write"],"parameters":[{"$ref":"#/components/parameters/CustomProviderId"},{"$ref":"#/components/parameters/CustomEndpointId"}],"responses":{"204":{"description":"Action deleted"},"403":{"description":"Feature, enterprise plan, owner, scope, or recent step-up requirement not met"},"404":{"description":"Custom provider or action not found in this workspace"}}}},"/credits/catalog":{"put":{"tags":["Catalog"],"summary":"Set the workspace default markup","operationId":"putCreditsCatalog","description":"Sets the tenant-wide default percentage and flat markup applied to every endpoint that has no provider or endpoint override. This is the base of the three-level precedence endpoint over provider over global that GET /credits/pricing/explain reports as markupSource. Send either field alone to change just that one; null restores the platform default.","security":[{"dashboardSession":[]},{"secretKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"properties":{"markupBps":{"type":["integer","null"],"minimum":0,"maximum":10000,"description":"Percentage markup in basis points, capped by the workspace markup ceiling. null restores the default."},"flatMarkupUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}],"description":"Flat per-call markup in USD. null restores the default."}},"additionalProperties":false}}}},"responses":{"200":{"description":"New workspace defaults","content":{"application/json":{"schema":{"type":"object","required":["success","scope","tenant"],"properties":{"success":{"const":true},"scope":{"const":"global"},"tenant":{"type":"object","required":["defaultMarkupBps","defaultFlatMarkupUsd","creditsPerDollar"],"properties":{"defaultMarkupBps":{"type":"integer"},"defaultFlatMarkupUsd":{"$ref":"#/components/schemas/DecimalString"},"creditsPerDollar":{"type":"integer"}},"additionalProperties":false}},"additionalProperties":false}}}},"400":{"description":"Unknown field, no field supplied, or a markup above the workspace ceiling."},"403":{"$ref":"#/components/responses/InsufficientScope"}}},"get":{"tags":["Catalog"],"summary":"List catalog with your effective prices","operationId":"getCreditsCatalog","description":"Use the default view=compact for normal enterprise catalog browsing. Compact responses omit executable JSON Schemas and model inventories, page providers, carry a version/ETag, and are gzip-compressed when the client advertises gzip. view=dashboard is the Locus Pro dashboard projection; its first page also publishes pageCursors so the dashboard can fetch the remaining pages concurrently. view=summary returns every provider as price-free card metadata and endpoint counts in one response. Agents should stay on compact and follow nextCursor; the 2026-08-31 revision only adds the optional provider secondaryCategories field, the 2026-09-05 revision adds `overridden` and `mcpPinned` to the dashboard endpoint plus the dashboard-only `enabled=true` filter, and the 2026-09-06 revision adds optional endpoint `billingModel` metadata. Personal accounts receive the price-safe dashboard projection when view is omitted or full/compact/dashboard is requested; they may also request summary. Request view=full only for the backward-compatible full export. Cache privately for at most 60 seconds and revalidate with If-None-Match; do not poll more often than once per minute.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"view","in":"query","schema":{"type":"string","enum":["compact","dashboard","summary","full"],"default":"compact"},"description":"The default is compact for enterprise workspaces and dashboard for personal accounts. Personal accounts are always projected to dashboard except for summary."},{"name":"cursor","in":"query","schema":{"type":"string","maxLength":512},"description":"Opaque provider cursor; valid only for the paged views (compact, dashboard)."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50},"description":"Provider page size; valid only for the paged views (compact, dashboard)."},{"name":"enabled","in":"query","schema":{"type":"boolean","const":true},"description":"view=dashboard only (personal accounts are always served that view): page over what the workspace has on. Every provider keeps only its enabled endpoints and is omitted when none is left; page cursors are computed over that list, and the response echoes filter.enabled so a client can tell a filtered page from one served by an older task. Any other view, or any value but true, is a 400."}],"responses":{"200":{"description":"Full export or compact provider page. Responses include ETag, X-Locus-Catalog-Version, and a private no-cache directive so enablement changes are never read from cache.","headers":{"ETag":{"schema":{"type":"string"}},"X-Locus-Catalog-Version":{"schema":{"type":"string","const":"2026-09-06"}},"Cache-Control":{"schema":{"type":"string","const":"private, no-cache"},"description":"The catalog is a mutable control surface: it always revalidates, so a read right after an enable/disable can never be served a stale body. The ETag keeps revalidation cheap (304, no body)."}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/CatalogResponse"},{"$ref":"#/components/schemas/CompactCatalogResponse"},{"$ref":"#/components/schemas/DashboardCatalogResponse"},{"$ref":"#/components/schemas/PersonalDashboardCatalogResponse"},{"$ref":"#/components/schemas/DashboardCatalogSummaryResponse"}]}}}},"304":{"description":"The tenant-scoped catalog page is unchanged."}}}},"/credits/catalog/{provider}":{"get":{"tags":["Catalog"],"summary":"Get one full provider catalog document","operationId":"getCreditsCatalogByProvider","description":"Fetches executable endpoint schemas and the reviewed model inventory only for the selected provider. For this operation, slug must be one provider ID. Use after the compact list, not as a polling endpoint.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":256}}],"responses":{"200":{"description":"Full enterprise detail or the price-safe personal projection","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/CatalogProviderDetailResponse"},{"$ref":"#/components/schemas/PersonalCatalogProviderDetailResponse"}]}}}},"304":{"description":"The tenant-scoped provider detail is unchanged."},"404":{"description":"Unknown provider."}}}},"/credits/catalog/bulk":{"put":{"tags":["Catalog"],"summary":"Enable or disable a bounded provider batch","operationId":"putCreditsCatalogBulk","description":"Creates or updates up to 50 provider-level enablement rows in one transaction, and resets those providers' endpoint-level enablement overrides to inherit so the value you send is the whole answer for every endpoint of every named provider. Endpoint-level MARKUP overrides are preserved. Clients split larger selections into bounded batches so edge inspection cannot reject an oversized request. Batches commit independently: a failure after an earlier batch committed leaves that batch applied.","security":[{"dashboardSession":[]},{"secretKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["providers","enabled"],"properties":{"providers":{"type":"array","minItems":1,"maxItems":50,"uniqueItems":true,"items":{"type":"string","minLength":1},"description":"Known provider slugs. Unknown providers reject the whole batch transaction."},"enabled":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Provider rows updated","content":{"application/json":{"schema":{"type":"object","required":["success","scope","enabled","updated","endpointOverridesCleared"],"properties":{"success":{"const":true},"scope":{"const":"bulk"},"enabled":{"type":"boolean"},"updated":{"type":"integer","minimum":1,"maximum":50},"endpointOverridesCleared":{"type":"integer","minimum":0,"description":"Endpoint-level enablement overrides reset to inherit by this batch."}},"additionalProperties":false}}}},"400":{"description":"Empty/oversized provider list or invalid enabled value"},"404":{"description":"At least one provider slug is unknown; no rows are updated"}}}},"/credits/catalog/batch":{"put":{"tags":["Catalog"],"summary":"Enable or disable a bounded set of slugs","operationId":"putCreditsCatalogBatch","description":"Enables or disables up to 50 slugs (provider ids or provider/endpoint) in one transaction, each with the row semantics of the single write: a provider entry converges its endpoint-level enablement overrides to inherit (and clears their MCP pins when it turns off); an endpoint entry writes its own row (and drops its own pin when it turns off). Markup overrides are preserved. Everything is validated before anything is written; entries apply in the order given; the response reports the effective enablement per entry. Open to personal accounts. Registered ahead of the provider routes, so batch is never read as a provider id.","security":[{"dashboardSession":[]},{"secretKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entries"],"properties":{"entries":{"type":"array","minItems":1,"maxItems":50,"items":{"type":"object","required":["slug","enabled"],"properties":{"slug":{"type":"string","minLength":1,"maxLength":512,"description":"A provider id or provider/endpoint. Slugs must be unique within a request."},"enabled":{"type":"boolean"}},"additionalProperties":false}}},"additionalProperties":false}}}},"responses":{"200":{"description":"Every entry written; enabled is what the burn and discovery paths now resolve per slug","content":{"application/json":{"schema":{"type":"object","required":["success","scope","updated","results"],"properties":{"success":{"const":true},"scope":{"const":"batch"},"updated":{"type":"integer","minimum":1,"maximum":50},"results":{"type":"array","minItems":1,"maxItems":50,"items":{"type":"object","required":["slug","enabled","scope"],"properties":{"slug":{"type":"string"},"enabled":{"type":"boolean"},"scope":{"type":"string","enum":["provider","endpoint"]}},"additionalProperties":false}}},"additionalProperties":false}}}},"400":{"description":"Empty or oversized entry list, a duplicate slug, or an unexpected body key"},"404":{"description":"At least one slug is unknown, named in the message; no rows are written"}}}},"/credits/catalog/changes":{"get":{"tags":["Catalog"],"summary":"Recent enablement changes with who made them","operationId":"getCreditsCatalogChanges","description":"The newest catalog enablement changes first: which tool or provider moved, from what to what, who did it (a member by email, an API key by name, an agent connection by name) and through which surface. Rows are written inside the transaction that moved the enablement and only when the state actually changed; the journal is append-only.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Newest rows to return; anything outside 1-200 is a 400."}],"responses":{"200":{"description":"Recent changes, newest first","content":{"application/json":{"schema":{"type":"object","required":["success","changes"],"properties":{"success":{"const":true},"changes":{"type":"array","maxItems":200,"items":{"$ref":"#/components/schemas/CatalogChange"}}},"additionalProperties":false}}}},"400":{"description":"limit outside 1-200"},"403":{"$ref":"#/components/responses/InsufficientScope"}}}},"/credits/catalog/changes/{requestId}/revert":{"post":{"tags":["Catalog"],"summary":"Put a journaled write back","operationId":"postCreditsCatalogChangesByRequestIdRevert","description":"Restores the rows one whole-catalog write moved, each to exactly what it held before (an explicit on or off, or inherit), and only where the write is still the last word on it: the row must read as the write left it (a turn-on left explicit on rows; a turn-off left provider rows off and the tool rows it converged at inherit) and no later write may have journaled the slug. Anything else was decided since and is skipped and counted, never clobbered. Rows are never deleted, so putting an earlier write back afterwards still finds them. A tool pinned now stays on and counts as skipped: putting a turn-on back never takes a pin away. Any other tool put back off drops its MCP pin; a tool put back on does not get its pin back, but pass the unpinned slugs the write answered with as repin and the answer names those that came back on. Only the id a whole-catalog write answered with (all-on:… or all-off:…) is accepted: other writers converge exceptions their journals do not record, so their state cannot be rebuilt exactly. The revert is journaled like any other write, under this request's id.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"requestId","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200},"description":"The requestId a whole-catalog write answered with (all-on:<revision>:… or all-off:<revision>:…)."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"repin":{"type":"array","maxItems":50,"items":{"type":"string","minLength":1,"maxLength":512},"description":"Tool slugs whose pins the write cleared (its unpinned answer)."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Rows restored where they still held; skipped counts rows decided since; repin names the asked-about tools now back on","content":{"application/json":{"schema":{"type":"object","required":["success","reverted","skipped","skippedSlugs","repin","requestId"],"properties":{"success":{"const":true},"reverted":{"type":"integer","minimum":0},"skipped":{"type":"integer","minimum":0},"skippedSlugs":{"type":"array","maxItems":200,"items":{"type":"string"},"description":"The first 200 slugs left alone because they were decided since; skipped is the full count."},"repin":{"type":"array","items":{"type":"string"},"description":"Of the slugs asked about, those whose tool this revert put back on."},"requestId":{"type":"string"}},"additionalProperties":false}}}},"400":{"description":"requestId empty, longer than 200 characters, or not one a whole-catalog write answered with; or a body that is not { repin?: string[] }"},"403":{"$ref":"#/components/responses/InsufficientScope"},"404":{"description":"No catalog changes are journaled for that request"}}}},"/credits/catalog/all":{"put":{"tags":["Catalog"],"summary":"Turn every mutable tool on or off","operationId":"putCreditsCatalogAll","description":"Moves every tool the workspace can switch in one transaction. enabled: true writes tool rows only: provider-level rows never move, so a tool added to a provider later still starts off. enabled: false writes every provider with a tool on at provider scope, resetting its endpoint-level enablement overrides to inherit and clearing their MCP pins, exactly as a provider entry of the batch route does. Markup overrides are preserved; always-on tools and custom endpoints are untouched. Every mutable provider is locked first, in one statement. The write is journaled under a fresh request id of its own, never the caller's x-request-id, and the response returns it so POST /credits/catalog/changes/{requestId}/revert can put exactly this write back. Open to personal accounts. Registered ahead of the provider routes, so all is never read as a provider id.","security":[{"dashboardSession":[]},{"secretKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Every tool not already there has moved; updated counts tools whose effective enablement changed, providers counts the providers touched","content":{"application/json":{"schema":{"type":"object","required":["success","scope","enabled","updated","providers","unpinned","requestId"],"properties":{"success":{"const":true},"scope":{"const":"all"},"enabled":{"type":"boolean"},"updated":{"type":"integer","minimum":0},"providers":{"type":"integer","minimum":0},"unpinned":{"type":"array","items":{"type":"string"},"description":"Tools whose MCP pins a turn-off cleared (empty for a turn-on). A revert restores enablement, not pins: the caller may pin these again."},"requestId":{"type":"string","pattern":"^all-(on|off):[0-9]+:","description":"The journal id of this write, naming its direction and its enablement revision, for the revert route."}},"additionalProperties":false}}}},"400":{"description":"enabled missing, not a boolean, or an unexpected body key"},"403":{"$ref":"#/components/responses/InsufficientScope"},"503":{"description":"Curation could not be read, even after reading it again; nothing was changed"}}}},"/credits/models/{provider}":{"get":{"tags":["Catalog"],"summary":"Read the reviewed inference model contract","operationId":"getCreditsModelsByProvider","description":"Returns Locus-supported model IDs, exact pricing dimensions, limits, route capabilities, request-field compatibility, deprecation state, and freshness metadata. This is a reviewed support boundary, not a pass-through of the provider's account-scoped model list.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"},"example":"openai"},{"name":"If-None-Match","in":"header","required":false,"schema":{"type":"string"},"description":"ETag returned by a previous model-catalog response."}],"responses":{"200":{"description":"Versioned inference model contract","headers":{"Cache-Control":{"schema":{"type":"string"},"description":"Private cache lifetime and stale-while-revalidate policy."},"ETag":{"schema":{"type":"string"},"description":"Strong validator for the complete catalog document."},"X-Locus-Model-Schema-Version":{"schema":{"type":"string"},"description":"Machine-readable schema version."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelCatalogResponse"}}}},"304":{"description":"Catalog is unchanged for the supplied If-None-Match value."},"404":{"description":"No reviewed model catalog exists for this provider."}}}},"/credits/catalog/{slug}":{"delete":{"tags":["Catalog"],"summary":"Clear a catalog override","operationId":"deleteCreditsCatalogBySlug","description":"Removes a provider or endpoint override so pricing falls back to the next level up, ending at the workspace default. slug is provider (whole provider) or provider/endpoint (URL-encoded), the same forms PUT accepts. Idempotent: clearing something that has no override succeeds and reports cleared: false. This clears configuration only — it never disables an endpoint.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"provider or provider/endpoint (URL-encoded)."}],"responses":{"200":{"description":"Override cleared, or already absent","content":{"application/json":{"schema":{"type":"object","required":["success","slug","cleared"],"properties":{"success":{"const":true},"slug":{"type":"string"},"cleared":{"type":"boolean","description":"false when there was no override to remove."}},"additionalProperties":false}}}},"403":{"$ref":"#/components/responses/InsufficientScope"},"404":{"description":"No such provider or endpoint in the Locus catalog. Clearing an override that was never set is not a 404 — that returns 200 with cleared: false."}}},"put":{"tags":["Catalog"],"summary":"Enable/disable or override markup","operationId":"putCreditsCatalogBySlug","description":"slug is `provider` (whole provider) or `provider/endpoint` (URL-encoded). Personal accounts must send exactly `{\"enabled\": boolean}` and receive only endpointSlug plus effective enabled state; markup fields and extra properties are rejected. Enterprise workspaces may update enablement and/or markup. Enablement resolves endpoint override -> provider override -> platform default. Omitting enabled never changes enablement. Sending enabled on a provider slug resets that provider's endpoint-level enablement overrides to inherit while preserving markup overrides.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/PersonalCatalogMutationRequest"},{"type":"object","title":"Enterprise catalog mutation","minProperties":1,"properties":{"enabled":{"type":"boolean"},"markupBps":{"type":"integer","minimum":0,"maximum":10000},"flatMarkupUsdc":{"$ref":"#/components/schemas/DecimalString"}},"additionalProperties":false}],"description":"The authenticated account tier selects the accepted branch."}}}},"responses":{"200":{"description":"Updated configuration","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/PersonalCatalogMutationResponse"},{"type":"object","title":"Enterprise catalog mutation response","required":["success","config"],"properties":{"success":{"const":true},"config":{"type":"object","required":["endpointSlug","enabled","enabledOverride","markupBps","flatMarkupUsdc"],"properties":{"endpointSlug":{"type":"string"},"enabled":{"type":"boolean","description":"Effective enablement after this write."},"enabledOverride":{"type":["boolean","null"],"description":"This row's override; null means inherit."},"markupBps":{"type":["integer","null"]},"flatMarkupUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]}},"additionalProperties":false}},"additionalProperties":false}]}}}}}}},"/credits/analytics":{"get":{"tags":["Ledger"],"summary":"Tenant usage analytics","operationId":"getCreditsAnalytics","description":"Exact database rollups over captured BURN debits. Accepts either the legacy days=7|30|90 form or an explicit half-open from/to window, optionally bucketed and narrowed to one spender and/or one provider. The prior comparison covers the same elapsed span as the current period, including today's partial UTC day, and is narrowed by the same filter so deltas stay like-for-like; top-ups, allocations, refunds, and open reservations are excluded. usageDrift is null when the optional detector read is temporarily unavailable.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","enum":[7,30,90],"default":30},"description":"Legacy form: N whole UTC days ending with today so far. Cannot be combined with from/to. Any value outside the enum — including a repeated parameter — is a 400 rather than a silent fall back to the default."},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"},"description":"Window start, inclusive. Strict ISO-8601 (must round-trip). Requires to. Must be on or after 2000-01-01T00:00:00.000Z."},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"},"description":"Window end, EXCLUSIVE. Strict ISO-8601. Requires from, must be later than it, and may not be more than 24 hours ahead of the server clock. A window ending in the future gap-fills its trailing buckets with zeros."},{"name":"bucket","in":"query","schema":{"type":"string","enum":["hour","day","week","month"],"default":"day"},"description":"Series granularity, aligned to UTC calendar boundaries (weeks start Monday). A window yielding more than 400 buckets is rejected."},{"name":"initiator","in":"query","schema":{"type":"string"},"description":"Spender reference <type>:<id>, where type is one of oauth_member, end_user, agent_connection, customer, credential, unattributed. The id is the identity analytics ranks by (external user id, Cognito sub, agent-connection id, API key id, or for a customer <URL-encoded attribution.source>/<customerId>, where an id without a slash means no source); unattributed takes no id."},{"name":"provider","in":"query","schema":{"type":"string"},"description":"Provider label as analytics reports it, including the literal 'Unknown service' for burns whose provider was never captured."},{"name":"endpoint","in":"query","schema":{"type":"string"},"description":"Endpoint name. Requires provider."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":10},"description":"Row cap applied to services, providers, users, and initiators."}],"responses":{"200":{"description":"Usage, cost, margin, service, and account rollups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsResponse"}}}},"400":{"description":"Unsupported range"}}}},"/credits/analytics/customers":{"get":{"tags":["Customers"],"summary":"Every customer with spend in a window","operationId":"getCreditsAnalyticsCustomers","description":"Each (attribution.source, customerId) pair the tenant's charges were attributed to in the window, counted exactly as analytics counts customer spend, named from the customer directory, filterable by product, searchable, and paged past the analytics row cap. sources totals every product with customer spend in the window and ignores source and q. Enterprise workspaces only.","security":[{"dashboardSession":[]},{"secretKey":[]}],"x-required-scopes":["tenant:read"],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","enum":[7,30,90],"default":30},"description":"Legacy form, as analytics. Cannot be combined with from/to."},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"},"description":"Window start, inclusive. Strict ISO-8601. Requires to."},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"},"description":"Window end, EXCLUSIVE. Strict ISO-8601. Requires from."},{"name":"source","in":"query","schema":{"type":"string","maxLength":128},"description":"Only this product's customers (attribution.source), exactly as tagged. Send it empty (source=) for customers with no product tag; omit it for every product."},{"name":"q","in":"query","schema":{"type":"string","maxLength":120},"description":"Case-insensitive literal substring of the directory name, the link, or the customer id."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":2147483647,"default":0}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"One page of customers, the matching total, and per-product totals","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["success","periodStart","periodEndExclusive","total","customers","sources"],"properties":{"success":{"type":"boolean","const":true},"periodStart":{"type":"string","format":"date-time"},"periodEndExclusive":{"type":"string","format":"date-time"},"total":{"type":"integer","description":"Customers matching source and q, across all pages."},"customers":{"type":"array","items":{"$ref":"#/components/schemas/CustomerSpend"}},"sources":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsCustomerSource"}}}}}}},"400":{"description":"Invalid window, page, source, or search"},"401":{"$ref":"#/components/responses/UnauthorizedManagement"},"403":{"$ref":"#/components/responses/InsufficientScope"},"503":{"description":"Too many analytics reads in flight; retry after Retry-After seconds"}}}},"/credits/ledger":{"get":{"tags":["Ledger"],"summary":"Tenant-wide ledger","operationId":"getCreditsLedger","description":"Lists double-entry ledger entries across the whole workspace, newest first, with cursor pagination. Filter by category, end user, initiator, provider and endpoint, creation window, attribution keys, ledger event kind, or the pooled platform account.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"category","in":"query","schema":{"type":"string","enum":["TOPUP","BURN","REFUND","CLAWBACK","FEE","ADJUSTMENT","ALLOCATION","PROMO"]}},{"name":"externalUserId","in":"query","schema":{"$ref":"#/components/schemas/ExternalUserId"}},{"name":"initiator","in":"query","schema":{"type":"string"},"description":"Spender reference <type>:<id>, matching the analytics initiator identity. Cannot be combined with externalUserId or account=platform; unattributed is not filterable."},{"name":"provider","in":"query","schema":{"type":"string"},"description":"Matches the provider recorded on the ledger entry. Legacy entries without provider metadata are excluded from this filtered ledger view."},{"name":"endpoint","in":"query","schema":{"type":"string"},"description":"metadata.endpoint equality. Requires provider."},{"name":"createdAfter","in":"query","schema":{"type":"string","format":"date-time"},"description":"Inclusive lower bound. Strict ISO-8601."},{"name":"createdBefore","in":"query","schema":{"type":"string","format":"date-time"},"description":"Exclusive upper bound. Strict ISO-8601."},{"name":"attribution.{key}","in":"query","schema":{"type":"string"},"description":"Equality filter on metadata.attribution.<key>, one query parameter per key: attribution.entityId=acct_889. Dot form only — bracket form is not parsed."},{"name":"sourceKey","in":"query","schema":{"type":"string"},"description":"Narrow to one ledger event kind, e.g. wapi_burn or stripe_topup."},{"name":"account","in":"query","schema":{"type":"string","enum":["platform"]},"description":"Restrict to the tenant's pooled platform account. Mutually exclusive with externalUserId and with an end-user initiator."},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Ledger page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantLedgerPage"}}}}}}},"/credits/ledger/summary":{"get":{"tags":["Ledger"],"summary":"Ledger row counts for a filter","operationId":"getCreditsLedgerSummary","description":"Counts the rows GET /credits/ledger would page through under the same filters. Cursor pagination can report neither a total nor a per-category split, which the Activity pager and its type chips need.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"category","in":"query","schema":{"type":"string","enum":["TOPUP","BURN","REFUND","CLAWBACK","FEE","ADJUSTMENT","ALLOCATION","PROMO"]}},{"name":"externalUserId","in":"query","schema":{"$ref":"#/components/schemas/ExternalUserId"}},{"name":"initiator","in":"query","schema":{"type":"string"},"description":"Spender reference <type>:<id>, matching the analytics initiator identity."},{"name":"provider","in":"query","schema":{"type":"string"}},{"name":"endpoint","in":"query","schema":{"type":"string"},"description":"Requires provider."},{"name":"createdAfter","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"createdBefore","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"attribution.{key}","in":"query","schema":{"type":"string"},"description":"Equality filter on metadata.attribution.<key>, one parameter per key. Dot form only."},{"name":"sourceKey","in":"query","schema":{"type":"string"}},{"name":"account","in":"query","schema":{"type":"string","enum":["platform"]}}],"responses":{"200":{"description":"Total row count, plus per-category counts and amounts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantLedgerSummary"}}}}}}},"/credits/webhooks/events":{"get":{"tags":["Webhooks"],"summary":"List durable webhook events","operationId":"getCreditsWebhooksEvents","description":"Lists durable webhook events for the workspace, newest first, with cursor pagination. Filter by event type to find an event before inspecting its delivery attempts.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"type","in":"query","schema":{"$ref":"#/components/schemas/WebhookEventType"}},{"name":"cursor","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Newest events first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEventPage"}}}}}}},"/credits/webhooks/events/{eventId}":{"get":{"tags":["Webhooks"],"summary":"Inspect an event and every delivery attempt","operationId":"getCreditsWebhooksEventsByEventId","description":"Returns one webhook event with its immutable envelope and every delivery attempt. Use it to debug failed deliveries. Returns 404 when the event belongs to another workspace.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Immutable envelope and delivery history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEventDetail"}}}},"404":{"description":"Event not found in this tenant"}}}},"/credits/webhooks/events/{eventId}/replay":{"post":{"tags":["Webhooks"],"summary":"Replay a retained event","operationId":"postCreditsWebhooksEventsByEventIdReplay","description":"Creates one new attempt using the same stable event ID and current endpoint. Returns 409 while another attempt is pending.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"202":{"description":"Replay attempted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEventDetail"}}}},"409":{"description":"An attempt is already pending or event retention expired"},"422":{"description":"Webhook endpoint is not configured"}}}},"/credits/customers":{"get":{"tags":["Customers"],"summary":"List the customer directory","operationId":"getCreditsCustomers","description":"Display data a tenant registered for the customers it attributes charges to (X-Locus-Attribution source and customerId), in creation order. Enterprise workspaces only.","security":[{"dashboardSession":[]},{"secretKey":[]}],"x-required-scopes":["tenant:read"],"parameters":[{"name":"source","in":"query","schema":{"type":"string","maxLength":128},"description":"Only this product's entries, exactly as stored. Send it empty (source=) for entries with no product; omit it for every product."},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"nextCursor from the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":100}}],"responses":{"200":{"description":"Directory entries","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["success","customers","nextCursor"],"properties":{"success":{"type":"boolean","const":true},"customers":{"type":"array","items":{"$ref":"#/components/schemas/CustomerDirectoryEntry"}},"nextCursor":{"type":["string","null"]}}}}}},"400":{"description":"Invalid cursor, limit, or source"},"401":{"$ref":"#/components/responses/UnauthorizedManagement"},"403":{"$ref":"#/components/responses/InsufficientScope"}}},"put":{"tags":["Customers"],"summary":"Name up to 50 customers","operationId":"putCreditsCustomers","description":"Upserts display data per (source, customerId). Charges keep only the ids, so a name can be corrected or removed later; the security audit records how many entries a write carried, never the entries themselves. The production edge rejects request bodies over 8 KiB, so send fewer entries when names or links are long. Enterprise workspaces only.","security":[{"dashboardSession":[]},{"secretKey":[]}],"x-required-scopes":["tenant:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["customers"],"properties":{"customers":{"type":"array","minItems":1,"maxItems":50,"items":{"$ref":"#/components/schemas/CustomerUpsert"}}}}}}},"responses":{"200":{"description":"Every entry was written","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["success","upserted"],"properties":{"success":{"type":"boolean","const":true},"upserted":{"type":"integer"}}}}}},"400":{"description":"An invalid entry, a duplicate (source, customerId), an unexpected key, or an empty or oversized batch; nothing is written"},"401":{"$ref":"#/components/responses/UnauthorizedManagement"},"403":{"$ref":"#/components/responses/InsufficientScope"}}}},"/credits/customers/remove":{"post":{"tags":["Customers"],"summary":"Forget up to 50 customers' names","operationId":"postCreditsCustomersRemove","description":"Deletes directory entries by (source, customerId). Charges are untouched; the dashboard shows the ids again. Enterprise workspaces only.","security":[{"dashboardSession":[]},{"secretKey":[]}],"x-required-scopes":["tenant:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["customers"],"properties":{"customers":{"type":"array","minItems":1,"maxItems":50,"items":{"$ref":"#/components/schemas/CustomerRef"}}}}}}},"responses":{"200":{"description":"How many of the named entries existed","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["success","removed"],"properties":{"success":{"type":"boolean","const":true},"removed":{"type":"integer"}}}}}},"400":{"description":"An invalid or duplicate entry, or an empty or oversized batch"},"401":{"$ref":"#/components/responses/UnauthorizedManagement"},"403":{"$ref":"#/components/responses/InsufficientScope"}}}},"/credits/end-users":{"get":{"tags":["End users"],"summary":"List end-users with balances","operationId":"getCreditsEndUsers","description":"Lists the workspace's end-user accounts with their balances, with cursor pagination. q filters by a case-insensitive substring of externalUserId.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"q","in":"query","schema":{"type":"string","maxLength":120},"description":"Case-insensitive substring match on externalUserId."},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","maximum":200,"default":50}}],"responses":{"200":{"description":"End-user accounts","content":{"application/json":{"schema":{"type":"object","required":["success","endUsers","nextCursor"],"properties":{"success":{"const":true},"endUsers":{"type":"array","items":{"$ref":"#/components/schemas/EndUserAccount"}},"nextCursor":{"type":["string","null"]}}}}}}}}},"/credits/end-users/{externalUserId}":{"delete":{"tags":["End users"],"summary":"Retire a test or integration end user without deleting financial history","operationId":"deleteCreditsEndUsersByExternalUserId","description":"Workspace owner or admin with fresh MFA/passkey step-up only. Fails closed unless the balance is zero and every reservation, top-up attempt, external purchase, and refund is terminal. Revokes end-user tokens and scoped agent credentials, cancels outstanding approvals, resets the operational policy, freezes the credit account, and marks the identity inactive. Ledger, funding, settlement, replay, and audit rows are retained. Repeating a completed retirement is safe.","security":[{"dashboardSession":[]}],"parameters":[{"name":"externalUserId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ExternalUserId"}},{"$ref":"#/components/parameters/WorkspaceStepUpHeader"}],"responses":{"200":{"description":"Retirement converged","content":{"application/json":{"schema":{"type":"object","required":["success","externalUserId","retired","alreadyRetired","accountId","revokedTokens","revokedAgentConnections","canceledApprovals","policyReset"],"properties":{"success":{"const":true},"externalUserId":{"$ref":"#/components/schemas/ExternalUserId"},"retired":{"type":"boolean"},"alreadyRetired":{"type":"boolean"},"accountId":{"type":["string","null"],"format":"uuid"},"revokedTokens":{"type":"integer","minimum":0},"revokedAgentConnections":{"type":"integer","minimum":0},"canceledApprovals":{"type":"integer","minimum":0},"policyReset":{"type":"boolean"}}}}}},"401":{"description":"Authentication required"},"403":{"description":"Workspace owner/admin role and fresh MFA/passkey step-up required"},"409":{"description":"Balance or asynchronous money work is still open"}}}},"/credits/end-users/{externalUserId}/token":{"post":{"tags":["End users"],"summary":"Mint an end-user token","operationId":"postCreditsEndUsersByExternalUserIdToken","description":"Mint server-side only. Creates the tenant-scoped end-user record and credit account on first use. JWT claims are sub, tid, iss=locus-credits, aud=locus-credits-enduser, iat, exp, jti, and optional sid. The sid claim is a SHA-256 fingerprint, not the raw session value. Verification allows 30 seconds of clock skew. There is no refresh token; re-authenticate the user and mint a replacement. A sid-bound token requires the original value in X-Locus-Session-Id whenever used.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"externalUserId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ExternalUserId"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndUserTokenRequest"}}}},"responses":{"200":{"description":"Token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndUserTokenResponse"}}}},"400":{"description":"Invalid externalUserId, expiresIn, sessionId, or unknown field"}}}},"/credits/end-users/{externalUserId}/policy":{"get":{"tags":["End users"],"summary":"Read an immutable end user's execution policy","operationId":"getCreditsEndUsersByExternalUserIdPolicy","description":"Returns the end user's current execution policy, or null when no policy is set. Policies are immutable; a change creates a new policy.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"externalUserId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ExternalUserId"}}],"responses":{"200":{"description":"Current policy or null","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndUserPolicyEnvelope"}}}}}},"put":{"tags":["End users"],"summary":"Create or replace an end user's execution policy","operationId":"putCreditsEndUsersByExternalUserIdPolicy","description":"Workspace owner/admin session or a secret key with tokens:manage. Admission, counters, the credit hold, and the reservation commit atomically. Amounts use the tenant's exact credit denomination.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"externalUserId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ExternalUserId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndUserPolicyInput"}}}},"responses":{"200":{"description":"Policy applied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndUserPolicyEnvelope"}}}},"400":{"description":"Unknown field or invalid exact-credit/count contract"}}},"delete":{"tags":["End users"],"summary":"Reset an end user's execution policy to no policy","operationId":"deleteCreditsEndUsersByExternalUserIdPolicy","description":"Workspace owner/admin session or a secret key with tokens:manage. Deletes operational policy counters only after all live reservations have captured or released. The append-only policy decision journal remains queryable by account. Repeating a completed reset is safe and returns reset=false.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"externalUserId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ExternalUserId"}}],"responses":{"200":{"description":"Policy is null","content":{"application/json":{"schema":{"type":"object","required":["success","externalUserId","policy","reset","priorPolicyId"],"properties":{"success":{"const":true},"externalUserId":{"$ref":"#/components/schemas/ExternalUserId"},"policy":{"type":"null"},"reset":{"type":"boolean"},"priorPolicyId":{"type":["string","null"],"format":"uuid"}}}}}},"409":{"description":"An active reservation must capture or release before reset"}}}},"/credits/end-users/{externalUserId}/policy/events":{"get":{"tags":["End users"],"summary":"List policy allow, deny, capture, release, and reset decisions","operationId":"getCreditsEndUsersByExternalUserIdPolicyEvents","description":"Lists the end user's policy decisions (allow, deny, capture, release, and reset), newest first. Use it to explain why a call was allowed or blocked.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"externalUserId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ExternalUserId"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":250,"default":100}}],"responses":{"200":{"description":"Newest policy decisions first","content":{"application/json":{"schema":{"type":"object","required":["success","externalUserId","events"],"properties":{"success":{"const":true},"externalUserId":{"$ref":"#/components/schemas/ExternalUserId"},"events":{"type":"array","items":{"$ref":"#/components/schemas/EndUserPolicyEvent"}}}}}}}}}},"/credits/end-users/{externalUserId}/allocate":{"post":{"tags":["End users"],"summary":"Allocate credits to an end-user","operationId":"postCreditsEndUsersByExternalUserIdAllocate","description":"Atomic platform-pool → end-user transfer; both sides ledgered. Fails (402) if the pool cannot cover it — unfunded allocations are impossible. Amounts are exact decimal strings.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"externalUserId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ExternalUserId"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"One key per logical transfer; reuse it on retries."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["credits"],"properties":{"credits":{"$ref":"#/components/schemas/DecimalString"},"promo":{"type":"boolean","description":"Ledger as a promo/comp grant"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Allocation applied; returns both balances","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferResult"}}}},"402":{"description":"Platform pool balance insufficient"}}}},"/credits/end-users/{externalUserId}/deallocate":{"post":{"tags":["End users"],"summary":"Reverse an allocation","operationId":"postCreditsEndUsersByExternalUserIdDeallocate","description":"Moves credits from the end user's balance back to the workspace platform pool, reversing an earlier allocation. Send amounts as decimal strings and reuse the same Idempotency-Key when retrying one logical transfer.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"externalUserId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ExternalUserId"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"One key per logical transfer; reuse it on retries."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["credits"],"properties":{"credits":{"$ref":"#/components/schemas/DecimalString"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Credits returned to the platform pool","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferResult"}}}}}}},"/credits/topups/quote":{"post":{"tags":["Top-ups"],"summary":"Quote a top-up (exact-decimal gross-up)","operationId":"postCreditsTopupsQuote","description":"Send exactly one exact decimal string: usd or credits. Numeric compatibility values are deprecated. Declare externalUserId when the eventual create targets an end user so the bonus fields match the create.","security":[{"dashboardSession":[]},{"secretKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupQuoteRequest"}}}},"responses":{"200":{"description":"Quote","content":{"application/json":{"schema":{"type":"object","required":["success","quote"],"properties":{"success":{"const":true},"quote":{"$ref":"#/components/schemas/TopupQuote"}}}}}},"400":{"$ref":"#/components/responses/TopupError"}}}},"/credits/topups/config":{"get":{"tags":["Top-ups"],"summary":"Get machine-readable top-up constraints","operationId":"getCreditsTopupsConfig","description":"Returns the workspace-specific top-up amount constraints and credit denomination. Read it before creating a checkout so the requested amount is valid.","security":[{"dashboardSession":[]},{"secretKey":[]}],"responses":{"200":{"description":"Tenant-specific amount constraints and denomination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupConstraintsEnvelope"}}}}}}},"/credits/topups":{"post":{"tags":["Top-ups"],"summary":"Create a hosted checkout session","operationId":"postCreditsTopups","description":"Canonical v2 contract. externalUserId present → end-user top-up. Absent → platform-pool self-top-up. Send exactly one exact-decimal usd or credits amount. There is no fixed or daily platform top-up ceiling. Evaluation funding does not activate a commercial agreement.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Reuse for retries of the same checkout creation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupRequest"}}}},"responses":{"201":{"description":"Checkout session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupSessionResponse"}}}},"400":{"description":"Validation or minimum-amount failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupErrorResponse"}}}}}}},"/credits/topups/{sessionId}":{"get":{"tags":["Top-ups"],"summary":"Get authoritative checkout state","operationId":"getCreditsTopupsBySessionId","description":"Returns the authoritative state of a workspace top-up checkout session. Poll it after Stripe Checkout instead of trusting the browser redirect.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","pattern":"^cs_"}}],"responses":{"200":{"description":"Checkout state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupStatus"}}}},"400":{"$ref":"#/components/responses/TopupError"}}}},"/credits/earnings":{"get":{"tags":["Ledger"],"summary":"Margin earnings","operationId":"getCreditsEarnings","description":"Returns the workspace margin earnings from end-user markup: accrued, matured, and paid out, as USD decimal strings.","security":[{"dashboardSession":[]},{"secretKey":[]}],"responses":{"200":{"description":"Accrued / matured / paid-out margin (USD decimal strings)","content":{"application/json":{"schema":{"type":"object","properties":{"accrued":{"type":"string"},"matured":{"type":"string"},"paidOut":{"type":"string"}}}}}}}}},"/credits/me/balance":{"get":{"tags":["Widget"],"summary":"Own balance (end-user)","operationId":"getCreditsMeBalance","description":"Returns the calling end user's own balance in the workspace's credit denomination. Authenticates with an end-user token, optionally alongside a publishable key for the browser widget.","security":[{"endUserToken":[]},{"endUserToken":[],"publishableKey":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"}],"responses":{"200":{"description":"Balance in the tenant's credit denomination","content":{"application/json":{"schema":{"type":"object","required":["success","balance"],"properties":{"success":{"const":true},"balance":{"type":"object","required":["externalUserId","balanceUsdc","balanceCredits","status"],"properties":{"externalUserId":{"$ref":"#/components/schemas/ExternalUserId"},"balanceUsdc":{"$ref":"#/components/schemas/DecimalString"},"balanceCredits":{"$ref":"#/components/schemas/DecimalString"},"status":{"type":"string","enum":["active","frozen"]}},"additionalProperties":false}},"additionalProperties":false}}}}}}},"/credits/me/catalog":{"get":{"tags":["Widget","Catalog"],"summary":"Discover APIs available to the authenticated end user","operationId":"getCreditsMeCatalog","description":"Versioned cursor catalog. Returns only endpoints enabled by the tenant and allowed by this end user's current provider policy. Omitted endpoints do not reveal whether they are disabled, denied, or unknown. Tenant rules, base USD cost, markup, and margin are never returned; price.usd is the final customer-visible effective price. Results sort by stable endpoint ID. Cursors are opaque, filters are exact/case-insensitive, and responses are private/non-cacheable so policy changes are visible on the next request. The end-user token authenticates this read on its own; when a publishable key is sent it must belong to the token's tenant.","security":[{"endUserToken":[]},{"endUserToken":[],"publishableKey":[]}],"parameters":[{"name":"provider","in":"query","schema":{"type":"string","maxLength":128},"description":"Exact stable provider ID (case-insensitive)"},{"name":"category","in":"query","schema":{"type":"string","maxLength":128},"description":"Exact provider category (case-insensitive)"},{"name":"cursor","in":"query","schema":{"type":"string","maxLength":512},"description":"Opaque cursor returned by the previous page"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Privacy-safe, policy-filtered provider catalog","headers":{"Cache-Control":{"schema":{"type":"string","const":"private, no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndUserCatalogResponse"}}}}}}},"/credits/me/ledger":{"get":{"tags":["Widget"],"summary":"Own ledger (end-user)","operationId":"getCreditsMeLedger","description":"Returns newest-first transaction history for the end user encoded in the bearer token. The caller cannot select another externalUserId. Entries include charges, top-ups, allocations, refunds, and other posted balance movements. End-user responses redact base cost, markup, margin, tenant identifiers, and internal pricing configuration.","security":[{"endUserToken":[]},{"endUserToken":[],"publishableKey":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"},{"name":"cursor","in":"query","description":"Opaque nextCursor from the previous page.","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of transaction-history entries to return.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"End-user transaction history with internal pricing fields redacted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LedgerPage"}}}}}}},"/credits/me/topups":{"post":{"tags":["Widget"],"summary":"Open a top-up for self (end-user)","operationId":"postCreditsMeTopups","description":"Identity is derived only from the end-user token. externalUserId is rejected.","security":[{"endUserToken":[]},{"endUserToken":[],"publishableKey":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupSelfRequest"}}}},"responses":{"201":{"description":"Checkout session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupSessionResponse"}}}},"400":{"description":"Validation or minimum-amount failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupErrorResponse"}}}}}}},"/credits/me/topups/config":{"get":{"tags":["Widget"],"summary":"Get machine-readable top-up constraints","operationId":"getCreditsMeTopupsConfig","description":"Returns the top-up amount constraints that apply to the calling end user. Read it before the end user starts a widget checkout.","security":[{"endUserToken":[]},{"endUserToken":[],"publishableKey":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"}],"responses":{"200":{"description":"Amount constraints","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupConstraintsEnvelope"}}}}}}},"/credits/me/topups/{sessionId}":{"get":{"tags":["Widget"],"summary":"Get authoritative state for this user's checkout","operationId":"getCreditsMeTopupsBySessionId","description":"Returns the authoritative state of one of the calling end user's own top-up checkout sessions. Poll it after checkout instead of trusting the browser redirect.","security":[{"endUserToken":[]},{"endUserToken":[],"publishableKey":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","pattern":"^cs_"}}],"responses":{"200":{"description":"Checkout state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupStatus"}}}},"400":{"$ref":"#/components/responses/TopupError"}}}},"/credits/catalog/search":{"post":{"tags":["Catalog"],"summary":"Search the management catalog","operationId":"postCreditsCatalogSearch","description":"Searches the built-in account-visible management catalog, including endpoints that are currently disabled. Enterprise-owned Custom APIs remain available through the catalog listing and detail routes but are not included in this static search index. Returns price-free display metadata, desired enablement, and current platform availability so a dashboard can help a person choose tools before enabling them. Always-on system routes are omitted; a tenant-toggleable Locus Travel route is included when available. This operation does not call a provider or burn credits.","security":[{"dashboardSession":[]},{"secretKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","minLength":1,"maxLength":256,"description":"Trimmed natural-language capability, provider, or endpoint query."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":30}},"additionalProperties":false}}}},"responses":{"200":{"description":"Ranked management results","headers":{"Cache-Control":{"schema":{"type":"string","const":"private, no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagementCatalogSearchResponse"}}}},"400":{"description":"Body must contain only a valid query and optional limit"},"401":{"description":"Missing or invalid management credential"},"403":{"$ref":"#/components/responses/InsufficientScope"},"500":{"description":"Catalog search failed"}}}},"/credits/tools/search":{"post":{"tags":["Catalog"],"summary":"Search executable and requestable tools","operationId":"postCreditsToolsSearch","description":"REST counterpart to MCP search_apis. Returns compact ranked summaries and routes a selected result through /credits/tools/describe. Workspace and agent principals see enabled and requestable disabled tools by default; end-user-bound callers see enabled tools only, and an account setting may choose enabled-only discovery. Results honor key endpoint allowlists, agent-connection scopes, and end-user policies. Secret keys require tenant:read rather than credits:move. This operation does not call a provider or burn credits.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"},{"name":"X-Locus-End-User","in":"header","required":false,"schema":{"$ref":"#/components/schemas/ExternalUserId"},"description":"Optional end-user identity for a tenant secret key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","minLength":1,"maxLength":256,"description":"Trimmed natural-language capability, provider, or tool query. Optional with category or pack."},"category":{"type":"string","minLength":1,"maxLength":120,"description":"Live canonical category ID or unambiguous alias."},"pack":{"type":"string","minLength":1,"maxLength":120,"description":"Live curated-pack ID or unambiguous alias."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10},"cursor":{"type":"string","minLength":1,"maxLength":500},"include_facets":{"type":"boolean","default":false}},"additionalProperties":false}}}},"responses":{"200":{"description":"Ranked compact tool summaries","headers":{"Cache-Control":{"schema":{"type":"string","const":"private, no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolSearchResponse"}}}},"400":{"description":"Invalid search scope, group, or scoped cursor"},"401":{"description":"Missing or invalid execution credential"},"500":{"description":"Tool search failed"}}}},"/credits/tools/describe":{"post":{"tags":["Catalog"],"summary":"Describe one selected tool","operationId":"postCreditsToolsDescribe","description":"Returns the full input schema, example, response contract, pricing, and next action for one principal-visible search result. Secret keys require tenant:read. This operation does not call a provider or burn credits.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"},{"name":"X-Locus-End-User","in":"header","required":false,"schema":{"$ref":"#/components/schemas/ExternalUserId"},"description":"Optional end-user identity for a tenant secret key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*/[A-Za-z0-9][A-Za-z0-9._-]*$"},"operation_query":{"type":"string","maxLength":256,"description":"Original search intent used to select the most relevant operation from a directory endpoint."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Full selected tool contract","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolDescribeResponse"}}}},"400":{"description":"Invalid slug"},"401":{"description":"Missing or invalid discovery credential"},"404":{"description":"Tool is not visible to this principal"},"500":{"description":"Tool description failed"}}}},"/credits/tools/estimate":{"post":{"tags":["Catalog"],"summary":"Quote one described tool","operationId":"postCreditsToolsEstimate","description":"Prices the intended request without dispatching it or burning credits. Variable-price and live external-rail tools may return an executable approval token or request a hard maximum before execution.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"},{"name":"X-Locus-End-User","in":"header","required":false,"schema":{"$ref":"#/components/schemas/ExternalUserId"},"description":"Optional end-user identity for a tenant secret key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*/[A-Za-z0-9][A-Za-z0-9._-]*$"},"body":{"type":"object","additionalProperties":true},"max_charge_credits":{"$ref":"#/components/schemas/DecimalString"},"preflight_external_quote":{"type":"boolean"},"idempotency_key":{"type":"string","minLength":1,"maxLength":200},"expires_in_seconds":{"type":"integer","minimum":30,"maximum":600}},"additionalProperties":false}}}},"responses":{"200":{"description":"No-dispatch price estimate or executable quote","headers":{"Cache-Control":{"schema":{"type":"string","const":"private, no-store"}}},"content":{"application/json":{"schema":{"type":"object","required":["success","estimate"],"properties":{"success":{"const":true},"estimate":{"type":"object","additionalProperties":true}},"additionalProperties":false}}}},"400":{"description":"Invalid endpoint arguments or quote controls"},"401":{"description":"Missing or invalid discovery credential"},"403":{"description":"Tool is disabled or denied for this principal"},"404":{"description":"Tool is not visible to this principal"},"500":{"description":"Tool estimate failed"}}}},"/credits/tools/groups":{"get":{"tags":["Catalog"],"summary":"List live executable categories and curated packs","operationId":"getCreditsToolsGroups","description":"Returns principal-scoped group metadata and executable counts. Discovery does not enable tools or widen permissions.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"name":"kind","in":"query","schema":{"type":"string","enum":["all","category","pack"],"default":"all"}},{"name":"query","in":"query","schema":{"type":"string","maxLength":120}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","schema":{"type":"string","maxLength":500}}],"responses":{"200":{"description":"Live group page","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid scoped cursor"},"401":{"description":"Missing or invalid execution credential"}}}},"/credits/tools/access-requests":{"post":{"tags":["Catalog"],"summary":"Request human approval to enable one disabled tool","operationId":"postCreditsToolsAccessRequests","description":"REST counterpart to MCP request_tool_access. Creates (or reissues) a short-lived approval link for one disabled endpoint. Send approval_url to a workspace member who can approve catalog changes; approval enables the tool in the caller's tool set. Poll GET /credits/tools/access-requests/{requestId} for the decision. Enables and calls nothing itself; free.","security":[{"secretKey":[]},{"agentConnection":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"type":"string","maxLength":256}},"additionalProperties":false}}}},"responses":{"200":{"description":"The tool is already enabled","headers":{"Cache-Control":{"schema":{"type":"string","const":"private, no-store"}}},"content":{"application/json":{"schema":{"type":"object","required":["success","status","slug","next_step"],"properties":{"success":{"const":true},"status":{"const":"already_enabled"},"slug":{"type":"string"},"renamed_from":{"type":"string"},"next_step":{"type":"object","additionalProperties":true}},"additionalProperties":false}}}},"201":{"description":"Approval link issued","headers":{"Cache-Control":{"schema":{"type":"string","const":"private, no-store"}}},"content":{"application/json":{"schema":{"type":"object","required":["success","status","slug","request_id","approval_url","expires_at","message"],"properties":{"success":{"const":true},"status":{"const":"pending_human_approval"},"slug":{"type":"string"},"renamed_from":{"type":"string"},"request_id":{"type":"string","format":"uuid"},"approval_url":{"type":"string","format":"uri"},"expires_at":{"type":"string","format":"date-time"},"message":{"type":"string"}},"additionalProperties":false}}}},"400":{"description":"Invalid endpoint slug"},"401":{"description":"Missing or invalid execution credential"},"403":{"description":"This credential cannot request workspace tool access"},"404":{"description":"Endpoint not found or unavailable"},"429":{"description":"Too many recent access requests from this credential"}}}},"/credits/tools/access-requests/{requestId}":{"get":{"tags":["Catalog"],"summary":"Read the decision on a tool access request","operationId":"getCreditsToolsAccessRequestsByRequestId","description":"Returns the current state of an access request issued in the caller's workspace. A pending request past expires_at reads as expired. enabled reports whether the tool is on in the requester's tool set right now.","security":[{"secretKey":[]},{"agentConnection":[]}],"parameters":[{"name":"requestId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Current request state","headers":{"Cache-Control":{"schema":{"type":"string","const":"private, no-store"}}},"content":{"application/json":{"schema":{"type":"object","required":["success","status","enabled","slug","expires_at"],"properties":{"success":{"const":true},"status":{"type":"string","enum":["pending","approved","denied","expired"]},"enabled":{"type":"boolean"},"slug":{"type":"string"},"expires_at":{"type":"string","format":"date-time"}},"additionalProperties":false}}}},"400":{"description":"Invalid request id"},"401":{"description":"Missing or invalid execution credential"},"404":{"description":"No such request in this workspace"}}}},"/credits/calls":{"get":{"tags":["Catalog"],"summary":"List your recent calls","operationId":"getCreditsCalls","description":"Returns recent calls newest first, with status and credits. Agent connections and OAuth clients see only their own calls. A secret key sees the whole account. Response bodies are never included; use the call result route for those.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":10}},{"name":"cursor","in":"query","schema":{"type":"string","maxLength":200}},{"name":"status","in":"query","schema":{"type":"string","enum":["charged","error","all"],"default":"all"}},{"name":"provider","in":"query","schema":{"type":"string","maxLength":128}}],"responses":{"200":{"description":"One page of calls","content":{"application/json":{"schema":{"type":"object","required":["success","calls","next_cursor"],"properties":{"success":{"type":"boolean"},"calls":{"type":"array","items":{"type":"object","required":["call_id","provider","endpoint","status","credits","created_at"],"properties":{"call_id":{"type":"string"},"provider":{"type":"string"},"endpoint":{"type":"string"},"status":{"type":"string"},"credits":{"$ref":"#/components/schemas/DecimalString"},"created_at":{"type":"string","format":"date-time"},"error_summary":{"type":"string"}}}},"next_cursor":{"type":["string","null"]}}}}}},"400":{"description":"Invalid query or cursor"},"401":{"description":"Missing or invalid credential"}}}},"/credits/bug-reports":{"post":{"tags":["Catalog"],"summary":"Report a bug or bad result","operationId":"postCreditsBugReports","description":"Sends a bug report to the Locus team. Each workspace can send 10 reports per hour.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["message"],"properties":{"message":{"type":"string","minLength":10,"maxLength":4000},"call_id":{"type":"string","maxLength":128},"tool":{"type":"string","maxLength":128},"context":{"type":"object","additionalProperties":true,"description":"Extra JSON, at most 8 KB."}}}}}},"responses":{"201":{"description":"Report received","content":{"application/json":{"schema":{"type":"object","required":["success","report_id","received"],"properties":{"success":{"type":"boolean"},"report_id":{"type":"string"},"received":{"type":"boolean"}}}}}},"400":{"description":"Invalid report"},"401":{"description":"Missing or invalid credential"},"429":{"description":"Too many reports in the last hour"}}}},"/credits/workflows/artifacts":{"post":{"tags":["Hosted Workflows"],"summary":"Upload a tenant-owned source or input artifact","operationId":"postCreditsWorkflowsArtifacts","description":"Accepts authenticated JSON content up to the configured artifact ceiling. It never fetches caller-supplied URLs.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["kind","content"],"properties":{"kind":{"type":"string","enum":["source","input"]},"content":{}},"additionalProperties":false}}}},"responses":{"201":{"description":"Tenant-scoped artifact metadata"},"400":{"description":"Invalid or oversized artifact"},"403":{"description":"Hosted Workflows unavailable or unauthorized"}}}},"/credits/workflows/artifacts/{artifactId}":{"get":{"tags":["Hosted Workflows"],"summary":"Read a bounded tenant-owned artifact page","operationId":"getCreditsWorkflowsArtifactsByArtifactId","description":"Returns metadata and one bounded content page of an artifact owned by the calling account. Use cursor and max_characters to page through large artifacts. Returns 404 for artifacts owned by another account.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"name":"artifactId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","schema":{"type":"string","maxLength":500}},{"name":"max_characters","in":"query","schema":{"type":"integer","minimum":1024,"maximum":20000,"default":20000}}],"responses":{"200":{"description":"Artifact metadata and content page"},"404":{"description":"Artifact is not owned by this account"}}}},"/credits/workflows":{"post":{"tags":["Hosted Workflows"],"summary":"Create a tenant-private Workflow draft","operationId":"postCreditsWorkflows","description":"Creates a private Workflow draft for the calling account from a source bundle. The draft is not runnable until it is checked and saved as an immutable version.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowCreateRequest"}}}},"responses":{"201":{"$ref":"#/components/responses/WorkflowObject"},"400":{"description":"Invalid source bundle"},"403":{"description":"Hosted Workflows unavailable or unauthorized"}}}},"/credits/workflows/{workflowId}":{"get":{"tags":["Hosted Workflows"],"summary":"Get a Workflow draft and its recent validation/version history","operationId":"getCreditsWorkflowsByWorkflowId","description":"Returns a Workflow draft owned by the calling account, with its recent validation and version history. Returns 404 for Workflows owned by another account.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/WorkflowId"}],"responses":{"200":{"$ref":"#/components/responses/WorkflowObject"},"404":{"description":"Workflow not found for this account"}}},"put":{"tags":["Hosted Workflows"],"summary":"Update a Workflow draft with optimistic concurrency","operationId":"putCreditsWorkflowsByWorkflowId","description":"Replaces the source of a Workflow draft. expected_revision must equal the current draft revision; otherwise the update fails with 409 and nothing changes.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/WorkflowId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["expected_revision","source"],"properties":{"expected_revision":{"type":"integer","minimum":1},"source":{"$ref":"#/components/schemas/WorkflowSource"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/WorkflowObject"},"409":{"description":"Draft revision conflict"}}}},"/credits/workflows/{workflowId}/validate":{"post":{"tags":["Hosted Workflows"],"summary":"Structurally check or fixture-test an exact draft revision","operationId":"postCreditsWorkflowsByWorkflowIdValidate","description":"check does not evaluate user code. fixtures runs in the fixed sandbox without live gateway authority or egress.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/WorkflowId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["revision","mode"],"properties":{"revision":{"type":"integer","minimum":1},"mode":{"type":"string","enum":["check","fixtures"]},"fixture_set":{"type":"string","maxLength":120}},"additionalProperties":false}}}},"responses":{"200":{"description":"Durable validation evidence"},"409":{"description":"Draft revision changed"}}}},"/credits/workflows/{workflowId}/versions":{"post":{"tags":["Hosted Workflows"],"summary":"Save an immutable checked Workflow version","operationId":"postCreditsWorkflowsByWorkflowIdVersions","description":"Saves the checked draft revision as an immutable Workflow version and returns its identity and validation evidence. The named revision must have passed its exact-revision check; otherwise the request fails with 409.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/WorkflowId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["revision"],"properties":{"revision":{"type":"integer","minimum":1}},"additionalProperties":false}}}},"responses":{"201":{"description":"Immutable version identity and validation evidence"},"409":{"description":"Successful exact-revision check required"}}}},"/credits/workflows/{workflowId}/runs":{"post":{"tags":["Hosted Workflows"],"summary":"Queue a bounded pilot or production run","operationId":"postCreditsWorkflowsByWorkflowIdRuns","description":"The run is a constrained child of the current connection and does not create another client or reusable credential.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/WorkflowId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowRunRequest"}}}},"responses":{"200":{"description":"Idempotent replay of the original run"},"202":{"$ref":"#/components/responses/WorkflowRunObject"},"409":{"description":"Idempotency or saved-version conflict"}}}},"/credits/workflow-runs":{"get":{"tags":["Hosted Workflows"],"summary":"List tenant-owned Workflow runs","operationId":"getCreditsWorkflowRuns","description":"Lists the calling account's Workflow runs as bounded summaries with a continuation cursor.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"cursor","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Bounded run summaries and continuation cursor"}}}},"/credits/workflow-runs/{runId}":{"get":{"tags":["Hosted Workflows"],"summary":"Inspect durable run state, metering, receipts, and artifact references","operationId":"getCreditsWorkflowRunsByRunId","description":"Returns the durable state of one Workflow run, including metering, receipts, and artifact references. Returns 404 for runs owned by another account.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/WorkflowRunId"}],"responses":{"200":{"$ref":"#/components/responses/WorkflowRunObject"},"404":{"description":"Run not found for this account"}}}},"/credits/workflow-runs/{runId}/cancel":{"post":{"tags":["Hosted Workflows"],"summary":"Stop new dispatch and request sandbox termination","operationId":"postCreditsWorkflowRunsByRunIdCancel","description":"Stops dispatching new work for the run and requests termination of its sandbox. Returns the updated run.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/WorkflowRunId"}],"responses":{"200":{"$ref":"#/components/responses/WorkflowRunObject"}}}},"/credits/workflow-runs/{runId}/resume":{"post":{"tags":["Hosted Workflows"],"summary":"Resume eligible unfinished work with current authorization","operationId":"postCreditsWorkflowRunsByRunIdResume","description":"Resumes a run's eligible unfinished work using the caller's current authorization. Returns 202 with the run, or 409 when the run cannot be resumed.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/WorkflowRunId"}],"responses":{"202":{"$ref":"#/components/responses/WorkflowRunObject"},"409":{"description":"Run is not resumable"}}}},"/credits/resources":{"get":{"tags":["Resources"],"summary":"List durable resources an agent bought","operationId":"getCreditsResources","description":"Rows are sorted newest first. End-user-bound callers see only their own resources. When auto_renews is true, billing renews the row on its own and expires_at is the next renewal.","security":[{"dashboardSession":[]},{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["all","active","expiring","released"],"default":"all"}},{"name":"service","in":"query","schema":{"type":"string","maxLength":128}},{"name":"end_user","in":"query","description":"Workspace callers only. An end-user-bound caller always sees only its own rows.","schema":{"type":"string","maxLength":256}},{"name":"cursor","in":"query","schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"Up to 50 resources and a next_cursor for the next page"},"401":{"description":"Missing or invalid credential"}}}},"/credits/resources/facets":{"get":{"tags":["Resources"],"summary":"List every service and end user you have resources under","operationId":"getCreditsResourcesFacets","description":"Use these to fill filters. Not narrowed by list filters. End-user-bound callers see only their own.","security":[{"dashboardSession":[]},{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"responses":{"200":{"description":"services and end_users, each a sorted list of strings"},"401":{"description":"Missing or invalid credential"}}}},"/credits/resources/{resourceId}":{"get":{"tags":["Resources"],"summary":"Read one resource, including its current renewal price","operationId":"getCreditsResourcesByResourceId","description":"Returns one resource owned by the caller, including its current renewal price. Returns 404 when the resource does not exist or belongs to someone else.","security":[{"dashboardSession":[]},{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"The resource"},"404":{"description":"Not found or not yours"}}}},"/credits/resources/{resourceId}/release":{"post":{"tags":["Resources"],"summary":"Release a resource through its provider","operationId":"postCreditsResourcesByResourceIdRelease","description":"The row is marked released only after the provider confirms, or answers that it is already gone.","security":[{"dashboardSession":[]},{"secretKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["idempotency_key"],"properties":{"idempotency_key":{"type":"string","minLength":1,"maxLength":255}}}}}},"responses":{"200":{"description":"Released, with the updated row"},"202":{"description":"Still processing; the row is returned unchanged"},"404":{"description":"Not found or not yours"}}}},"/credits/resources/{resourceId}/renew":{"post":{"tags":["Resources"],"summary":"Renew a resource, refused before any charge above max_cost_usd","operationId":"postCreditsResourcesByResourceIdRenew","description":"Read the resource first and pass its renewal.price_usd as max_cost_usd. A higher price at renewal time is refused before any charge.","security":[{"dashboardSession":[]},{"secretKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["idempotency_key","max_cost_usd"],"properties":{"idempotency_key":{"type":"string","minLength":1,"maxLength":255},"max_cost_usd":{"$ref":"#/components/schemas/DecimalString"}}}}}},"responses":{"200":{"description":"Renewed, with the updated row"},"202":{"description":"Still processing; the row is returned unchanged"},"404":{"description":"Not found or not yours"},"409":{"description":"charge_ceiling_exceeded: the live price exceeds max_cost_usd"}}}},"/agent/guides/manifest.json":{"get":{"tags":["Agent-native onboarding"],"summary":"Get the immutable public Locus guide release manifest","operationId":"getAgentGuidesManifestJson","description":"Public, unauthenticated. Returns the immutable manifest of the current Locus guide release: guide IDs, resources, media types, digests, and URLs. Agents use it to fetch exact, digest-verified guide versions.","security":[],"responses":{"200":{"description":"Versioned guide IDs, resources, media types, digests, and URLs"}}}},"/agent/compatibility.json":{"get":{"tags":["Agent-native onboarding"],"summary":"Get independently versioned platform compatibility","operationId":"getAgentCompatibilityJson","description":"Public, unauthenticated. Returns independently versioned compatibility information for the API, taxonomy, guide bundle, plugins, runtimes, SDKs, and Workflow availability. Agents read it to choose a supported integration path.","security":[],"responses":{"200":{"description":"API, taxonomy, guide bundle, plugin, runtime, SDK, and Workflow availability"}}}},"/agent/guides/{bundleVersion}/{guideId}.md":{"get":{"tags":["Agent-native onboarding"],"summary":"Read one public guide resource as Markdown or text","operationId":"getAgentGuidesByBundleVersionByGuideIdM","description":"Public, unauthenticated. Returns the bytes of one guide from a specific guide bundle version as Markdown or plain text. Content is digest-addressed by the release manifest.","security":[],"parameters":[{"$ref":"#/components/parameters/GuideBundleVersion"},{"$ref":"#/components/parameters/GuideId"}],"responses":{"200":{"description":"Digest-addressed guide bytes"},"404":{"description":"Unknown guide or bundle version"}}}},"/agent/guides/{bundleVersion}/{guideId}.json":{"get":{"tags":["Agent-native onboarding"],"summary":"Read one public guide resource as a JSON envelope","operationId":"getAgentGuidesByBundleVersionByGuideIdJso","description":"Public, unauthenticated. Returns one guide from a specific guide bundle version as a JSON envelope with its metadata, content, resources, and digest.","security":[],"parameters":[{"$ref":"#/components/parameters/GuideBundleVersion"},{"$ref":"#/components/parameters/GuideId"}],"responses":{"200":{"description":"Guide metadata, content, resources, and digest"},"404":{"description":"Unknown guide or bundle version"}}}},"/agent/guides/{bundleVersion}/{guideId}/content":{"get":{"tags":["Agent-native onboarding"],"summary":"Read one public guide resource using its declared media type","operationId":"getAgentGuidesByBundleVersionByGuideIdContent","description":"Public, unauthenticated. Returns the bytes of one guide or template from a specific guide bundle version, served with the media type declared in the release manifest.","security":[],"parameters":[{"$ref":"#/components/parameters/GuideBundleVersion"},{"$ref":"#/components/parameters/GuideId"}],"responses":{"200":{"description":"Digest-addressed guide or template bytes"},"404":{"description":"Unknown guide or bundle version"}}}},"/credits/md":{"get":{"tags":["Burn"],"summary":"Per-tenant generated docs (markdown)","operationId":"getCreditsMd","description":"Enterprise workspace documentation for enabled endpoints and effective tenant pricing. Requires a management credential with tenant:read; personal accounts and end-user JWTs cannot use this route.","security":[{"dashboardSession":[]},{"secretKey":[]}],"parameters":[{"name":"provider","in":"query","schema":{"type":"string"},"description":"Provider detail page"}],"responses":{"200":{"description":"Markdown","content":{"text/markdown":{"schema":{"type":"string"}}}},"403":{"description":"Enterprise tier or tenant:read scope required"},"404":{"description":"Unknown or disabled provider"}}}},"/.well-known/oauth-protected-resource/api/credits/mcp":{"get":{"tags":["MCP"],"summary":"Discover the MCP protected resource","operationId":"getWellKnownOauthProtectedResourceApiCreditsMcp","description":"Canonical RFC 9728 path derived from the MCP resource identifier.","servers":[{"url":"https://api.paywithlocus.com","description":"Production origin"},{"url":"https://api.stage.paywithlocus.com","description":"Stage origin"}],"security":[],"responses":{"200":{"description":"Protected-resource metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpProtectedResourceMetadata"}}}}}}},"/.well-known/oauth-authorization-server/api/credits/mcp/oauth":{"get":{"tags":["MCP"],"summary":"Discover the MCP authorization server","operationId":"getWellKnownOauthAuthorizationServerApiCreditsMcpOauth","description":"Canonical RFC 8414 path derived from the MCP OAuth issuer.","servers":[{"url":"https://api.paywithlocus.com","description":"Production origin"},{"url":"https://api.stage.paywithlocus.com","description":"Stage origin"}],"security":[],"responses":{"200":{"description":"Authorization-server metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpAuthorizationServerMetadata"}}}}}}},"/credits/mcp/.well-known/oauth-protected-resource":{"get":{"tags":["MCP"],"summary":"Discover the MCP protected resource (compatibility alias)","operationId":"getCreditsMcpWellKnownOauthProtectedResource","description":"API-prefixed compatibility alias for the canonical RFC 9728 metadata path.","security":[],"responses":{"200":{"description":"Protected-resource metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpProtectedResourceMetadata"}}}}}}},"/credits/mcp/oauth/.well-known/oauth-authorization-server":{"get":{"tags":["MCP"],"summary":"Discover the MCP authorization server (compatibility alias)","operationId":"getCreditsMcpOauthWellKnownOauthAuthorizationServer","description":"API-prefixed compatibility alias for the canonical RFC 8414 metadata path.","security":[],"responses":{"200":{"description":"Authorization-server metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpAuthorizationServerMetadata"}}}}}}},"/credits/mcp/oauth/device_authorization":{"post":{"tags":["MCP"],"summary":"Start MCP device authorization","operationId":"postCreditsMcpOauthDeviceAuthorization","description":"RFC 8628 authorization for a headless public client registered with the device-code grant. Send the exact MCP resource. Locus returns a 15-minute device code, a human-readable user code, and a five-second initial polling interval. Do not send client authentication.","security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/McpOAuthDeviceAuthorizationRequest"}}}},"responses":{"200":{"description":"Pending device authorization","headers":{"Cache-Control":{"schema":{"const":"no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthDeviceAuthorizationResponse"}}}},"400":{"description":"Invalid client, resource, scope, or grant registration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}},"401":{"description":"Unknown client or an Authorization header was supplied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}},"415":{"description":"Content type must be application/x-www-form-urlencoded"}}}},"/credits/mcp/oauth/device/public-context":{"get":{"tags":["MCP"],"summary":"Read signed-out device authorization context","operationId":"getCreditsMcpOauthDevicePublicContext","description":"Returns only the pending client's public name, ID, requested scopes, resource, and expiry for a valid user code. It exposes no Locus identity, membership, or tenant data.","security":[],"parameters":[{"$ref":"#/components/parameters/McpDeviceUserCodeQuery"}],"responses":{"200":{"description":"Safe public context","headers":{"Cache-Control":{"schema":{"const":"no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthDevicePublicContextResponse"}}}},"400":{"description":"User code is invalid, expired, or no longer pending","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}},"429":{"description":"Too many verification attempts"}}}},"/credits/mcp/oauth/device/tenants":{"get":{"tags":["MCP"],"summary":"List memberships available to a device authorization","operationId":"getCreditsMcpOauthDeviceTenants","description":"Signed-in consent helper. Returns active Locus Pro memberships so a person with more than one account can make an explicit selection. It does not approve the device.","security":[{"dashboardSession":[]}],"parameters":[{"$ref":"#/components/parameters/McpDeviceUserCodeQuery"},{"$ref":"#/components/parameters/LocusTenantSelectionHeader"}],"responses":{"200":{"description":"Available memberships and current selection","headers":{"Cache-Control":{"schema":{"const":"no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthDeviceTenantListResponse"}}}},"400":{"description":"Invalid/expired user code or missing signed-in user"},"401":{"description":"Dashboard session required"},"403":{"description":"No active Locus Pro membership is available"},"429":{"description":"Too many verification attempts"}}}},"/credits/mcp/oauth/device/context":{"get":{"tags":["MCP"],"summary":"Read signed-in device consent context","operationId":"getCreditsMcpOauthDeviceContext","description":"Returns the selected account, grantable scopes, connection capacity, resource, and expiry immediately before a human approves or denies the device. Requested scopes may be reduced to the member's effective authority.","security":[{"dashboardSession":[]}],"parameters":[{"$ref":"#/components/parameters/McpDeviceUserCodeQuery"},{"$ref":"#/components/parameters/LocusTenantSelectionHeader"}],"responses":{"200":{"description":"Device consent context","headers":{"Cache-Control":{"schema":{"const":"no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthDeviceContextResponse"}}}},"400":{"description":"Invalid/expired user code, invalid account selection, or missing signed-in user"},"401":{"description":"Dashboard session required"},"403":{"description":"Selected membership is unavailable"},"429":{"description":"Too many verification attempts"}}}},"/credits/mcp/oauth/device/decision":{"post":{"tags":["MCP"],"summary":"Approve or deny an MCP device authorization","operationId":"postCreditsMcpOauthDeviceDecision","description":"Resolves one pending device request for the explicitly selected active membership. Approval reserves connection-plan capacity until the client exchanges the device code or the 15-minute request expires. A same-client retry by the same person supersedes its unfinished reservation.","security":[{"dashboardSession":[]}],"parameters":[{"$ref":"#/components/parameters/LocusTenantSelectionHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["userCode","allow"],"properties":{"userCode":{"$ref":"#/components/schemas/McpOAuthDeviceUserCodeInput"},"allow":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Request approved or denied","headers":{"Cache-Control":{"schema":{"const":"no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthDeviceDecisionResponse"}}}},"400":{"description":"Invalid/expired user code, invalid account selection, or missing signed-in user"},"401":{"description":"Dashboard session required"},"403":{"description":"Selected membership is unavailable"},"409":{"description":"The request was already resolved or the account has no connection capacity"},"429":{"description":"Too many verification attempts"}}}},"/credits/mcp/oauth/authorize":{"get":{"tags":["MCP"],"summary":"Start MCP OAuth authorization","operationId":"getCreditsMcpOauthAuthorize","description":"Starts the public-client Authorization Code flow. PKCE S256 and the exact MCP resource indicator are required; the browser is redirected to Locus consent and then back to the registered redirect URI.","security":[],"parameters":[{"name":"response_type","in":"query","required":true,"schema":{"type":"string","const":"code"}},{"name":"client_id","in":"query","required":true,"schema":{"type":"string","maxLength":2048}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string","format":"uri","maxLength":2048}},{"name":"code_challenge","in":"query","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{43,128}$"}},{"name":"code_challenge_method","in":"query","required":true,"schema":{"type":"string","const":"S256"}},{"name":"resource","in":"query","required":true,"schema":{"type":"string","format":"uri"},"description":"Exact Locus Pro MCP resource URL."},{"name":"scope","in":"query","required":false,"schema":{"type":"string","maxLength":512,"example":"mcp:read mcp:execute offline_access"}},{"name":"state","in":"query","required":false,"schema":{"type":"string","maxLength":2048}}],"responses":{"302":{"description":"Redirect to consent, or to the registered redirect URI with an OAuth error"},"400":{"description":"Invalid client or request before a safe redirect URI can be established","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}}}}},"/credits/mcp/oauth/authorize/public-context":{"get":{"tags":["MCP"],"summary":"Read safe signed-out context for an MCP authorization","operationId":"getCreditsMcpOauthAuthorizePublicContext","description":"Returns the non-sensitive client, scope, resource, expiry, and AgentID continuation URL for a pending OAuth request. Browserless agent-owned accounts use this endpoint after the MCP client starts Authorization Code + PKCE; it exposes no tenant or identity information.","security":[],"parameters":[{"name":"request","in":"query","required":true,"schema":{"type":"string","pattern":"^lmo_req_[A-Za-z0-9_-]{43}$"}}],"responses":{"200":{"description":"Safe context for a live pending authorization","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":false,"required":["clientName","clientId","scopes","resource","expiresAt","agentIdAuthorizationUrl"],"properties":{"clientName":{"type":"string"},"clientId":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"resource":{"type":"string","format":"uri"},"expiresAt":{"type":"string","format":"date-time"},"agentIdAuthorizationUrl":{"type":"string","format":"uri"}}}}}}}},"400":{"description":"Authorization request is malformed, expired, or already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}}}}},"/credits/mcp/oauth/authorize/agentid":{"get":{"tags":["MCP"],"summary":"Continue a pending MCP authorization with AgentID","operationId":"getCreditsMcpOauthAuthorizeAgentid","description":"Builds the AgentID Authorization Code + PKCE request for a pending Locus MCP authorization and redirects to AgentID. AgentID is the resource-owner login for an already activated agent-owned account.","security":[],"parameters":[{"name":"request","in":"query","required":true,"schema":{"type":"string","pattern":"^lmo_req_[A-Za-z0-9_-]{43}$"}}],"responses":{"302":{"description":"Redirect to AgentID"},"400":{"description":"Authorization request is malformed, expired, or already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}},"503":{"description":"AgentID sign-in is temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}}}}},"/credits/mcp/oauth/authorize/agent-credential":{"post":{"tags":["MCP"],"summary":"Approve a pending MCP authorization with the agent's own credential","operationId":"postCreditsMcpOauthAuthorizeAgentCredential","description":"For an agent that created its own workspace (POST /credits/agent/signup or /credits/agent/register). The agent sends the lmo_req_ handle from its MCP client's authorization redirect with the lcac_ credential it received at signup, and receives the client's redirect URL with an authorization code. Credentials a person issued from the dashboard are refused. The resulting connection ends when that credential is revoked, expires, or the human declines the account.","security":[{"agentConnection":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["request"],"properties":{"request":{"type":"string","pattern":"^lmo_req_[A-Za-z0-9_-]{43}$"}}}}}},"responses":{"200":{"description":"Approved; deliver redirectUrl to the waiting MCP client exactly as returned"},"400":{"description":"Authorization request is malformed, expired, or already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}},"403":{"description":"Not the credential the agent received when it created its workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}},"409":{"description":"Connection limit reached or request already resolved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}}}}},"/credits/mcp/oauth/token":{"post":{"tags":["MCP"],"summary":"Exchange or refresh an MCP OAuth token","operationId":"postCreditsMcpOauthToken","description":"Public-client token endpoint. Client secrets and Authorization headers are not supported. Authorization-code exchange requires the PKCE verifier; device clients poll no faster than the returned interval and handle authorization_pending, slow_down, access_denied, and expired_token; refresh tokens rotate on every successful use.","security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/McpOAuthTokenRequest"}}}},"responses":{"200":{"description":"Resource-bound bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthTokenResponse"}}}},"400":{"description":"Invalid request, grant, target, or grant type","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}},"401":{"description":"Unknown client or unsupported client authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}},"415":{"description":"Content type must be application/x-www-form-urlencoded"}}}},"/credits/mcp/oauth/register":{"post":{"tags":["MCP"],"summary":"Dynamically register an MCP OAuth client","operationId":"postCreditsMcpOauthRegister","description":"RFC 7591 registration for public native or web clients. Register authorization_code with validated redirect URIs, the RFC 8628 device-code grant without redirect URIs, or both. refresh_token is optional; offline_access is grantable only when it is registered.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthClientMetadata"}}}},"responses":{"201":{"description":"Registered client and one-time registration access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthClientRegistration"}}}},"400":{"description":"Invalid client metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}},"415":{"description":"Content type must be application/json"}}}},"/credits/mcp/oauth/register/{clientId}":{"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["MCP"],"summary":"Read a dynamic MCP client registration","operationId":"getCreditsMcpOauthRegisterByClientId","description":"Returns the current metadata of a dynamically registered MCP OAuth client (RFC 7592). Authenticate with the registration access token returned when the client was created.","security":[{"mcpRegistrationToken":[]}],"responses":{"200":{"description":"Current registration metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthClientRegistration"}}}},"401":{"description":"Missing or invalid registration access token"}}},"put":{"tags":["MCP"],"summary":"Replace a dynamic MCP client registration","operationId":"putCreditsMcpOauthRegisterByClientId","description":"Replaces the metadata of a dynamically registered MCP OAuth client (RFC 7592). Authenticate with the registration access token returned when the client was created.","security":[{"mcpRegistrationToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthClientMetadataUpdate"}}}},"responses":{"200":{"description":"Updated registration metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthClientRegistration"}}}},"400":{"description":"Invalid client metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}},"401":{"description":"Missing or invalid registration access token"}}},"delete":{"tags":["MCP"],"summary":"Delete a dynamic MCP client registration","operationId":"deleteCreditsMcpOauthRegisterByClientId","description":"Deletes the registration and revokes its active authorization and token families.","security":[{"mcpRegistrationToken":[]}],"responses":{"204":{"description":"Registration deleted"},"401":{"description":"Missing or invalid registration access token"}}}},"/credits/mcp/oauth/revoke":{"post":{"tags":["MCP"],"summary":"Revoke an MCP OAuth token family","operationId":"postCreditsMcpOauthRevoke","description":"RFC 7009-style public-client revocation. Revoking an access or refresh token revokes its token family; unknown tokens still return success.","security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["token","client_id"],"properties":{"token":{"type":"string"},"client_id":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"description":"Revocation processed"},"400":{"description":"token and client_id are required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpOAuthError"}}}},"415":{"description":"Content type must be application/x-www-form-urlencoded"}}}},"/credits/mcp/docs":{"get":{"tags":["MCP"],"summary":"Machine-readable MCP connection guide","operationId":"getCreditsMcpDocs","description":"Public, cacheable description of the hosted MCP server: its URL, the OAuth discovery document locations, the scope model and token lifetimes, and ready-to-paste configuration for Claude Code, Codex, Cursor, VS Code, and Gemini CLI. Point an agent at this instead of hard-coding setup steps.","security":[],"responses":{"200":{"description":"Connection guide","headers":{"Cache-Control":{"schema":{"const":"public, max-age=300"}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["name","server_url","resource_metadata","authorization_server_metadata"],"properties":{"name":{"const":"Locus Pro MCP"},"server_url":{"type":"string","format":"uri"},"resource_metadata":{"type":"string","format":"uri","description":"RFC 9728 protected-resource metadata URL."},"authorization_server_metadata":{"type":"string","format":"uri","description":"RFC 8414 authorization-server metadata URL."},"client_configurations":{"type":"object","additionalProperties":true},"scopes":{"type":"object","additionalProperties":true},"oauth_lifecycle":{"type":"object","additionalProperties":true}}}}}}}}},"/credits/mcp":{"post":{"tags":["MCP"],"summary":"Hosted MCP server (stateless Streamable HTTP)","operationId":"postCreditsMcp","description":"One MCP JSON-RPC request per POST, with an encoded JSON body limit of 4 MiB. OAuth 2.1 is the primary authentication path: initialize, discovery, and resource reads require mcp:read, while billed tools/call execution additionally requires mcp:execute. Tenant secret keys, end-user JWTs, and scoped agent connections remain compatibility credentials. This transport is stateless: it issues no MCP-Session-Id, retains no resumable SSE stream, and recomputes the authenticated tenant catalog on every request. For tools/call, inspect result.isError even when HTTP and JSON-RPC both succeeded.","security":[{"mcpOAuth":["mcp:read"]},{"secretKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"},{"name":"MCP-Protocol-Version","in":"header","required":false,"schema":{"type":"string","example":"2025-06-18"},"description":"Negotiated MCP version on requests after initialize. The server also accepts 2025-03-26 clients."},{"name":"Accept","in":"header","required":true,"schema":{"type":"string","example":"application/json, text/event-stream"},"description":"Streamable HTTP clients advertise both media types. This stateless server returns application/json."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpJsonRpcRequest"},"examples":{"listTools":{"value":{"jsonrpc":"2.0","id":"list-1","method":"tools/list","params":{}}},"callTool":{"value":{"jsonrpc":"2.0","id":"call-1","method":"tools/call","params":{"name":"execute","arguments":{"slug":"tavily/search","args":{"query":"agent payment infrastructure"},"idempotency_key":"job-42-search","max_credits":"100"}}}}}}}},"responses":{"200":{"description":"JSON-RPC success or protocol error. A tools/call application failure is a success envelope whose result.isError is true.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/McpJsonRpcSuccess"},{"$ref":"#/components/schemas/McpJsonRpcError"}]}}}},"202":{"description":"Accepted MCP notification; no JSON-RPC response body."},"400":{"description":"Malformed JSON-RPC or unsupported Streamable HTTP request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpJsonRpcError"}}}},"401":{"description":"OAuth authorization is missing or invalid, or a compatibility secret-key, end-user, or agent-connection credential is invalid. Sandbox and publishable keys are not accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpJsonRpcError"}}}},"403":{"description":"The OAuth token lacks mcp:read or, for billed tools/call, mcp:execute; or an authenticated compatibility principal is denied by tenant, origin, or policy controls.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpJsonRpcError"}}}},"405":{"description":"POST is the only supported method; stateless sessions cannot be fetched or deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpJsonRpcError"}}}},"413":{"description":"Encoded JSON request exceeds the 4 MiB Locus Pro execution limit","content":{"application/json":{"schema":{"type":"object","required":["success","error","code","limitBytes"],"properties":{"success":{"const":false},"error":{"const":"Payload too large"},"code":{"const":"REQUEST_BODY_TOO_LARGE"},"limitBytes":{"const":4194304}},"additionalProperties":false}}}},"500":{"description":"Request-scoped MCP transport failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpJsonRpcError"}}}}}},"get":{"tags":["MCP"],"summary":"Unsupported in stateless mode","operationId":"getCreditsMcp","description":"The hosted MCP server is stateless, so it offers no standalone SSE stream to resume. Authenticated requests receive 405. Send MCP JSON-RPC messages with POST instead.","security":[{"mcpOAuth":["mcp:read"]},{"secretKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"}],"responses":{"401":{"description":"Missing or invalid OAuth or compatibility credential"},"403":{"description":"OAuth scope, origin, tenant, or policy denied the request"},"405":{"description":"No resumable session or SSE stream exists"}}},"delete":{"tags":["MCP"],"summary":"Unsupported in stateless mode","operationId":"deleteCreditsMcp","description":"The hosted MCP server is stateless and keeps no server-side session to delete. Authenticated requests receive 405.","security":[{"mcpOAuth":["mcp:read"]},{"secretKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"}],"responses":{"401":{"description":"Missing or invalid OAuth or compatibility credential"},"403":{"description":"OAuth scope, origin, tenant, or policy denied the request"},"405":{"description":"No server-side session exists to delete"}}}},"/wrapped/credits/v1/chat/completions":{"post":{"tags":["Burn"],"summary":"OpenAI-compatible metered chat completions","operationId":"postWrappedCreditsV1ChatCompletions","description":"Accepts the OpenAI Chat Completions request shape. With stream=true, returns provider-native SSE without full-response buffering. Locus captures the fixed authorized charge before delivering the first byte.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"},"description":"One key per model request body; reuse it on an identical retry."},{"name":"X-Locus-End-User","in":"header","required":false,"schema":{"$ref":"#/components/schemas/ExternalUserId"}},{"name":"X-Locus-Agent-Loop-Id","in":"header","required":false,"schema":{"type":"string","maxLength":200},"description":"Required when this user's policy sets maxCallsPerLoop."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAIChatCompletionRequest"}}}},"responses":{"200":{"description":"OpenAI JSON response, or unbuffered OpenAI SSE when stream=true","headers":{"X-Locus-Api-Call-Id":{"schema":{"type":"string","format":"uuid"}},"X-Locus-Credits-Charged":{"schema":{"$ref":"#/components/schemas/DecimalString"},"description":"Final charge on a JSON response. Not sent on a stream, which settles after delivery."},"X-Locus-Credits-Balance":{"schema":{"$ref":"#/components/schemas/DecimalString"},"description":"Balance after a JSON response is charged. Not sent on a stream."},"X-Locus-Credits-Reserved":{"schema":{"$ref":"#/components/schemas/DecimalString"},"description":"Stream only: the hold. The charge, read from X-Locus-Stream-Status-Url after the stream ends, never exceeds it."},"X-Locus-Stream-Billing":{"schema":{"const":"settled-after-delivery"}},"X-Locus-Stream-Status-Url":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"text/event-stream":{"schema":{"type":"string","description":"OpenAI data: JSON chunks followed by data: [DONE]. Text and tool_calls deltas are passed through byte-for-byte. After [DONE], one final `event: locus.billing` whose data is {\"object\":\"locus.billing\",\"choices\":[],\"locus_billing\":{apiCallId, chargedCredits, balanceCredits?, settlement: captured|deferred, statusUrl}} carries the settled charge; the status URL remains the source of truth."}}}},"400":{"description":"Local request validation or provider validation error before stream delivery"},"402":{"description":"Insufficient credits; no provider dispatch"},"403":{"description":"Endpoint or native end-user policy denied execution"},"409":{"description":"Idempotency conflict or stream_not_replayable status response"},"413":{"description":"Encoded JSON request exceeds the 4 MiB Locus Pro chat limit","content":{"application/json":{"schema":{"type":"object","required":["success","error","code","limitBytes"],"properties":{"success":{"const":false},"error":{"const":"Payload too large"},"code":{"const":"REQUEST_BODY_TOO_LARGE"},"limitBytes":{"const":4194304}},"additionalProperties":false}}}},"429":{"description":"Tenant or provider rate limit before stream delivery"},"503":{"description":"Provider configuration or stream settlement pending, or a provider/transport failure or timeout before stream delivery with the reservation released. Locus sends gateway failures as 503 so the JSON body passes the edge; X-Locus-Origin-Status carries the original 502 or 504."}}}},"/wrapped/credits/locus-travel/flight-search/preview":{"post":{"tags":["Travel routing"],"summary":"Plan a multi-provider flight search without dispatching","operationId":"postWrappedCreditsLocusTravelFlightSearchPreview","description":"Feature-gated Locus Travel planning route. It validates the normalized search, applies credential and catalog restrictions, selects eligible providers, and returns the aggregate estimated charge. It does not contact travel providers or burn credits. estimateExact is false when at least one selected provider has a live or otherwise variable price.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"},{"name":"X-Locus-End-User","in":"header","required":false,"schema":{"$ref":"#/components/schemas/ExternalUserId"},"description":"Optional end-user identity for a tenant secret or sandbox key. It must agree with body externalUserId when both are present."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TravelFlightSearchRequest"}}}},"responses":{"200":{"description":"No-dispatch provider plan and aggregate estimate","headers":{"Cache-Control":{"schema":{"const":"private, no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TravelFlightSearchPreview"}}}},"400":{"description":"Invalid flight search"},"401":{"description":"Missing or invalid execution credential"},"403":{"description":"Account, end-user, Agent Connection, or endpoint policy denied access"},"409":{"description":"The planned provider calls exceed maxCredits or another credential-level charge ceiling"}}}},"/wrapped/credits/locus-travel/flight-search":{"post":{"tags":["Travel routing"],"summary":"Search flights across selected providers","operationId":"postWrappedCreditsLocusTravelFlightSearch","description":"Feature-gated system-managed capability router. Locus plans eligible providers, executes them concurrently, normalizes and deduplicates itineraries, ranks offers, and returns aggregate billing. Use the preview route first when you need an estimate. A narrower request maxCredits or credential-level ceiling prevents dispatch when the aggregate estimate is too high. Retries must reuse the same Idempotency-Key and identical logical request; a 202 response means one or more child providers are still processing, so retry with the same key.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"},"description":"One key per logical travel search. Reuse it with an identical request to replay or finish the run."},{"name":"X-Locus-End-User","in":"header","required":false,"schema":{"$ref":"#/components/schemas/ExternalUserId"},"description":"Optional end-user identity for a tenant secret or sandbox key. It must agree with body externalUserId when both are present."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TravelFlightSearchRequest"}}}},"responses":{"200":{"description":"Normalized, ranked flight search with provider outcomes and aggregate billing","headers":{"X-Locus-Router-Run-Id":{"schema":{"type":"string","format":"uuid"}},"X-Locus-Router-Capability":{"schema":{"const":"travel.flight_search"}},"X-Locus-Router-Dispatches":{"schema":{"type":"integer","minimum":0}},"X-Locus-Credits-Charged":{"schema":{"$ref":"#/components/schemas/DecimalString"}},"X-Locus-Credits-Balance":{"schema":{"$ref":"#/components/schemas/DecimalString"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TravelFlightSearchResponse"}}}},"202":{"description":"The durable run is still processing; retry with the same Idempotency-Key","headers":{"Retry-After":{"schema":{"type":"integer","const":2}},"X-Locus-Router-Run-Id":{"schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TravelFlightSearchPending"}}}},"400":{"description":"Invalid search, missing/invalid Idempotency-Key, or caller-correctable request error"},"401":{"description":"Missing or invalid execution credential"},"403":{"description":"Account, end-user, Agent Connection, catalog, or endpoint policy denied execution"},"409":{"description":"Idempotency-Key belongs to a different request or the planned aggregate charge exceeds a ceiling"},"503":{"description":"All selected travel providers failed; per-provider outcomes and any incurred child billing are returned. X-Locus-Origin-Status: 502."}}}},"/wrapped/credits/locus-travel/flight-search/{runId}/feedback":{"post":{"tags":["Travel routing"],"summary":"Submit feedback for a completed flight search","operationId":"postWrappedCreditsLocusTravelFlightSearchByRunIdFeedback","description":"Creates or replaces feedback for a completed run owned by the authenticated account. selectedItineraryId, when supplied, must belong to that run. End-user and Agent Connection access remains scoped exactly as it was for execution.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"$ref":"#/components/parameters/SessionBindingHeader"},{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Locus-End-User","in":"header","required":false,"schema":{"$ref":"#/components/schemas/ExternalUserId"},"description":"Secret or sandbox keys must repeat the run's end-user identity, when any."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TravelFlightSearchFeedbackRequest"}}}},"responses":{"200":{"description":"Feedback saved","headers":{"Cache-Control":{"schema":{"const":"no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TravelFlightSearchFeedbackResponse"}}}},"400":{"description":"Invalid run ID, feedback, or itinerary ID"},"401":{"description":"Missing or invalid execution credential"},"403":{"description":"The credential is not allowed to access Locus Travel feedback"},"404":{"description":"No matching run is visible to this account"},"409":{"description":"The travel search has not completed"}}}},"/wrapped/credits/calls/{callId}":{"get":{"tags":["Burn"],"summary":"Read authoritative stream state and final billing","operationId":"getWrappedCreditsCallsByCallId","description":"Returns the authoritative state of a streamed wrapped call and its final credit values once billing settles. Secret-key callers must repeat the original X-Locus-End-User header. Returns 404 when the call belongs to another credit account.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"name":"callId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/SessionBindingHeader"},{"name":"X-Locus-End-User","in":"header","required":false,"schema":{"$ref":"#/components/schemas/ExternalUserId"},"description":"Secret-key callers must repeat the original end user."}],"responses":{"200":{"description":"Call ownership verified; state and final credit values returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditsCallStatus"}}}},"404":{"description":"Call not found for this credit account"}}}},"/wrapped/credits/calls/{callId}/result":{"post":{"tags":["Burn"],"summary":"Read async job result","operationId":"postWrappedCreditsCallsByCallIdResult","description":"Read the provider result of an async job, such as clado/bulk-contacts. Pass the apiCallId returned by the submit call. Locus reads the job id from that call's receipt. Reads are free and never create a new charge, so polling the same call again is safe. Access follows the submit endpoint's scope. Set waitSeconds to wait on the server for up to 45 seconds. When state is pending, call again after pollAfterMs. When nextPage is present, call again with its skip and limit to read the next page. A call that started no provider job, such as a call sent with Prefer: respond-async, returns its own stored outcome instead: state, the httpStatus and body the call would have returned, and billing for the read.","security":[{"secretKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"name":"callId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The apiCallId of the submit call."},{"$ref":"#/components/parameters/SessionBindingHeader"},{"name":"X-Locus-End-User","in":"header","required":false,"schema":{"$ref":"#/components/schemas/ExternalUserId"},"description":"Secret-key callers must repeat the original end user."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"waitSeconds":{"type":"integer","minimum":0,"maximum":45,"default":0,"description":"Seconds to wait on the server for the job to finish. 0 reads the current state once."},"skip":{"type":"integer","minimum":0,"description":"Result offset for paged results. Copy it from nextPage."},"limit":{"type":"integer","minimum":1,"description":"Results per page for paged results. Copy it from nextPage."}}}}}},"responses":{"200":{"description":"Job state and provider result. No credits charged.","content":{"application/json":{"schema":{"oneOf":[{"type":"object","description":"A call that started a provider job.","required":["apiCallId","provider","endpoint","statusEndpoint","jobId","state","result","billing"],"properties":{"apiCallId":{"type":"string","format":"uuid"},"provider":{"type":"string"},"endpoint":{"type":"string","description":"The submit endpoint."},"statusEndpoint":{"type":"string","description":"The provider status endpoint Locus read."},"jobId":{"type":"string"},"state":{"type":"string","enum":["pending","completed","failed"]},"pollAfterMs":{"type":"integer","description":"Present when state is pending."},"nextPage":{"type":"object","required":["skip"],"properties":{"skip":{"type":"integer"},"limit":{"type":"integer"}},"description":"Present when more result pages remain. Pass these values as skip and limit."},"result":{"description":"The provider status body. When state is completed it holds the final result."},"billing":{"type":"object","required":["chargedCredits"],"properties":{"chargedCredits":{"type":"string"}}}}},{"type":"object","description":"A call that started no provider job: its stored outcome.","required":["apiCallId","state","billing"],"properties":{"apiCallId":{"type":"string","format":"uuid"},"state":{"type":"string","enum":["pending","completed","failed"]},"pollAfterMs":{"type":"integer","description":"Present when state is pending: the call is still running."},"httpStatus":{"type":"integer","description":"The HTTP status the call returned. Present unless state is pending."},"result":{"description":"The body the call returned: the provider response, or the Locus error body when state is failed. Present unless state is pending."},"billing":{"type":"object","required":["chargedCredits"],"properties":{"chargedCredits":{"type":"string","description":"Charge for this read (always 0). The call's own charge is on GET /wrapped/credits/calls/{callId}."}}}}}]}}}},"400":{"description":"Invalid waitSeconds, skip, or limit (invalid_request), or skip or limit sent for a result that is not paged (pagination_unsupported)","content":{"application/json":{"schema":{"type":"object","required":["error","code","message"],"properties":{"error":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Credential cannot call the submit endpoint (credential_endpoint_denied)","content":{"application/json":{"schema":{"type":"object","required":["error","code","message"],"properties":{"error":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"No call or job for this call id is visible to this credential, or the provider no longer has the job (job_not_found)","content":{"application/json":{"schema":{"type":"object","required":["error","code","message"],"properties":{"error":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}}}},"424":{"description":"The provider status read failed. Retry; reads are free (upstream_error)","content":{"application/json":{"schema":{"type":"object","required":["error","code","message"],"properties":{"error":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}}}},"429":{"description":"Tenant rate limit exceeded"}}}},"/wrapped/credits/{provider}/{endpoint}":{"post":{"tags":["Burn"],"summary":"Metered pay-per-use call","operationId":"postWrappedCreditsByProviderByEndpoint","description":"The response body is the RAW upstream response (byte-compatible with the provider SDK shape). Cost rides in response headers. `X-Locus-End-User` present (or an end-user token or end-user-bound Agent Connection) charges that user's account at your effective price; a secret-key call without it or a platform-mode Agent Connection charges your platform account at base price with zero markup.","security":[{"secretKey":[]},{"sandboxKey":[]},{"endUserToken":[]},{"agentConnection":[]}],"parameters":[{"name":"X-Locus-Max-Charge-Credits","in":"header","required":false,"schema":{"type":"string","pattern":"^(?:0|[1-9]\\d{0,24})(?:\\.\\d{1,6})?$"},"description":"Hosted wrapped APIs: hard per-call ceiling in tenant credits, including applicable markup. Rejected with 409 charge_ceiling_exceeded before reservation or upstream dispatch if exceeded. Applies to fal generation reservations. Not forwarded upstream."},{"$ref":"#/components/parameters/SessionBindingHeader"},{"name":"provider","in":"path","required":true,"schema":{"type":"string"}},{"name":"endpoint","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"},"description":"Required. Missing → 400. Same key + different body → 409. Retries replay the stored outcome for 24 hours after the call; after that the key is released and reusing it starts a new call."},{"name":"Prefer","in":"header","required":false,"schema":{"type":"string","example":"respond-async"},"description":"respond-async: answer 202 with the apiCallId once the provider request is sent, and finish the call in the background. Read the outcome from resultUrl (POST /wrapped/credits/calls/{callId}/result). Anything decided before dispatch (validation, balance, policy, a replay) answers as usual. Ignored when stream is true."},{"name":"X-Locus-End-User","in":"header","required":false,"schema":{"$ref":"#/components/schemas/ExternalUserId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Upstream-shaped request body (see the per-endpoint docs at /credits/md)"}}}},"responses":{"200":{"description":"Raw upstream response. For fal/generate this acknowledges queue submission: credits remain reserved until a background reconciler confirms the result. Confirmed failures release the hold; successful results capture it. Read /wrapped/credits/calls/{callId} for settlement status.","headers":{"X-Locus-Credits-Reserved":{"schema":{"type":"string"},"description":"Credits held for a queued fal generation. Charged is zero at submission; available balance excludes this hold."},"X-Locus-Credits-Charged":{"schema":{"type":"string"},"description":"Charged amount in the tenant's credit denomination"},"X-Locus-Credits-Balance":{"schema":{"type":"string"},"description":"Remaining balance in credits"},"X-Locus-Cost-Usd":{"schema":{"type":"string"},"description":"Base cost in USD — tenant secret/sandbox credentials and platform-mode Agent Connections only"},"X-Locus-Model":{"schema":{"type":"string"},"description":"Inference model reported by the provider, when available"},"X-Locus-Finish-Reason":{"schema":{"type":"string"},"description":"Normalized provider finish or stop reason, when available"},"X-Locus-Input-Tokens":{"schema":{"type":"integer","minimum":0},"description":"Provider-reported input tokens"},"X-Locus-Visible-Output-Tokens":{"schema":{"type":"integer","minimum":0},"description":"Output tokens excluding provider-reported reasoning tokens"},"X-Locus-Reasoning-Tokens":{"schema":{"type":"integer","minimum":0},"description":"Provider-reported hidden reasoning or thinking tokens"},"X-Locus-Billed-Tokens":{"schema":{"type":"integer","minimum":0},"description":"Provider-reported total billed tokens"}}},"202":{"description":"Prefer: respond-async was applied. The provider request is out and the call finishes in the background. A same-key retry while it runs answers 202 again. Headers: Preference-Applied, Location (statusUrl), Retry-After, X-Locus-Api-Call-Id.","content":{"application/json":{"schema":{"type":"object","required":["apiCallId","status","statusUrl","resultUrl","pollAfterMs"],"properties":{"apiCallId":{"type":"string","format":"uuid"},"status":{"const":"in_progress"},"statusUrl":{"type":"string","description":"GET for settlement status."},"resultUrl":{"type":"string","description":"POST for the stored outcome; accepts waitSeconds."},"pollAfterMs":{"type":"integer"}}}}}},"400":{"description":"Missing Idempotency-Key, locally invalid request, or caller-correctable upstream validation error","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/UpstreamWrapperError"},{"type":"object","additionalProperties":true}]}}}},"402":{"description":"Insufficient credits","content":{"application/json":{"schema":{"type":"object","required":["error","message","requiredCredits","availableCredits","docsUrl"],"properties":{"error":{"const":"Insufficient credits"},"message":{"type":"string"},"requiredCredits":{"$ref":"#/components/schemas/DecimalString"},"availableCredits":{"$ref":"#/components/schemas/DecimalString"},"docsUrl":{"type":"string","format":"uri"}},"additionalProperties":false}}}},"403":{"description":"The call was refused before dispatch and no credits moved. Either the endpoint is disabled for this tenant or outside the credential's scope, or the workspace has reached its monthly spend limit — the latter carries code TENANT_MONTHLY_SPEND_LIMIT_EXCEEDED and is terminal until resetsAt.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/WorkspaceSpendLimitDenial"},{"type":"object","additionalProperties":true,"description":"Endpoint disabled, out of credential scope, or denied by the end user's execution policy."}]}}}},"409":{"description":"Idempotency-Key reused with a different body, or charge_ceiling_exceeded before any reservation or provider dispatch"},"422":{"description":"Caller-correctable upstream validation error; credits are released","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpstreamWrapperError"}}}},"503":{"description":"Provider gateway failure: Locus sends a provider 502 or 504 as 503 so the edge passes the JSON error body (code, upstreamStatus, apiCallId, and providerError.code when the provider sent one) through; X-Locus-Origin-Status carries the original status and credits are released. Also fal_queue_receipt_persistence_pending: submission was dispatched but neither receipt copy could be persisted. Credits remain held. Retry with the same Idempotency-Key or read statusUrl; do not create a new job. An unrecoverable receipt releases its hold after 24 hours and reports UNCONFIRMED."}}}}},"components":{"securitySchemes":{"secretKey":{"type":"http","scheme":"bearer","description":"Tenant secret key (lcr_…). Server-side only."},"sandboxKey":{"type":"http","scheme":"bearer","description":"Sandbox key (lcrsb_…). Metered calls are simulated: no credits move, no providers are called. No management access. Simulation is served from fixtures for the hosted provider catalog; external-rail providers are not registered with the sandbox interceptor and answer 404."},"endUserToken":{"type":"http","scheme":"bearer","description":"60-3600 second end-user JWT minted via /credits/end-users/{id}/token. If the JWT has sid, send the original session value in X-Locus-Session-Id; sid contains only its SHA-256 fingerprint. Bearer tokens are replayable until expiry; use short TTLs, optional session binding, and Idempotency-Key on operations."},"publishableKey":{"type":"apiKey","in":"header","name":"X-Locus-Publishable-Key","description":"Widget calls: rides alongside the end-user token."},"dashboardSession":{"type":"http","scheme":"bearer","description":"Locus Pro dashboard session (Cognito). High-risk workspace administration requires an owner or admin role and fresh MFA/passkey step-up."},"mcpOAuth":{"type":"oauth2","description":"Primary authentication for the hosted MCP resource. Public clients use Authorization Code with PKCE S256. mcp:read covers discovery and resource reads; billed tools/call additionally requires mcp:execute; offline_access requests a rotating refresh token.","flows":{"authorizationCode":{"authorizationUrl":"https://api.paywithlocus.com/api/credits/mcp/oauth/authorize","tokenUrl":"https://api.paywithlocus.com/api/credits/mcp/oauth/token","refreshUrl":"https://api.paywithlocus.com/api/credits/mcp/oauth/token","scopes":{"mcp:read":"Discover and read the authenticated MCP catalog and resources.","mcp:execute":"Execute billed MCP tools.","offline_access":"Issue and rotate a persistent refresh token."}}}},"mcpRegistrationToken":{"type":"http","scheme":"bearer","description":"Dynamic-client registration access token returned once when the MCP OAuth client is created. It remains valid only for that client's registration management URI."},"agentConnection":{"type":"http","scheme":"bearer","description":"Scoped lcac_ credential. Tenant-managed Agent Connections authorize only their bound MCP and wrapped execution surfaces. A bootstrap connection for a self-registered agent additionally authorizes the explicit /credits/agent/* self-service routes for its own account; neither form authorizes general tenant management."},"okibiIdentity":{"type":"http","scheme":"bearer","bearerFormat":"Okibi capability","description":"Short-lived capability injected only by an Identity-eligible signed Okibi CLI release. It is verified by @okibi/partner-kit for issuer, audience, installation, grant activity, and required route scopes. Never persist or copy it into native Locus configuration."}},"parameters":{"AgentConnectionId":{"name":"connectionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"CustomProviderId":{"name":"providerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Workspace-owned custom provider ID. This is distinct from its public custom-{slug} catalog name."},"CustomEndpointId":{"name":"endpointId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Workspace-owned custom action ID."},"McpDeviceUserCodeQuery":{"name":"user_code","in":"query","required":true,"schema":{"$ref":"#/components/schemas/McpOAuthDeviceUserCodeInput"},"description":"Six-character device user code. Input is case-insensitive; non-alphanumeric punctuation is ignored and the value is normalized to XXX-XXX."},"LocusTenantSelectionHeader":{"name":"X-Locus-Tenant-Id","in":"header","required":false,"schema":{"type":"string","format":"uuid"},"description":"Explicit account selection for a signed-in identity with multiple active memberships."},"WorkspaceStepUpHeader":{"name":"X-Locus-Step-Up","in":"header","required":false,"schema":{"type":"string","format":"password"},"description":"Short-lived raw MFA/passkey step-up token bound to the authenticated Cognito subject. Send it alongside the dashboard Bearer token for workspace-administrator mutations when the base session does not itself prove MFA within the last ten minutes. Never send it with a tenant secret key."},"SessionBindingHeader":{"name":"X-Locus-Session-Id","in":"header","required":false,"schema":{"type":"string","minLength":16,"maxLength":128,"pattern":"^[A-Za-z0-9][A-Za-z0-9._:-]{15,127}$"},"description":"Required only when the end-user JWT carries sid. Send the original high-entropy session value; sid is its SHA-256 fingerprint. Ignored for secret-key authentication."},"WorkflowId":{"name":"workflowId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"WorkflowRunId":{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"ResourceId":{"name":"resourceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"GuideBundleVersion":{"name":"bundleVersion","in":"path","required":true,"schema":{"type":"string","maxLength":40}},"GuideId":{"name":"guideId","in":"path","required":true,"schema":{"type":"string","maxLength":80}}},"responses":{"UnauthorizedManagement":{"description":"Missing, invalid, expired, or revoked management credential"},"InsufficientScope":{"description":"The authenticated management credential lacks one or more required scopes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsufficientScopeError"}}}},"EvaluationPayoutLocked":{"description":"Evaluation payouts and Stripe Connect are disabled until a commercial agreement is active","content":{"application/json":{"schema":{"type":"object","required":["success","error","code","message"],"properties":{"success":{"const":false},"error":{"const":"Evaluation payouts locked"},"code":{"const":"evaluation_payout_locked"},"message":{"type":"string"}}}}}},"TopupError":{"description":"Stable top-up validation, velocity, or ownership error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupError"}}}},"WorkflowObject":{"description":"Tenant-scoped Workflow definition envelope","content":{"application/json":{"schema":{"type":"object","required":["success","workflow"],"properties":{"success":{"const":true},"workflow":{"type":"object","additionalProperties":true}},"additionalProperties":false}}}},"WorkflowRunObject":{"description":"Tenant-scoped durable Workflow run envelope","content":{"application/json":{"schema":{"type":"object","required":["success","run"],"properties":{"success":{"const":true},"replay":{"type":"boolean"},"run":{"type":"object","additionalProperties":true}},"additionalProperties":false}}}}},"schemas":{"WorkflowFile":{"type":"object","required":["path","content"],"properties":{"path":{"type":"string","minLength":1},"content":{"type":"string"}},"additionalProperties":false},"WorkflowSource":{"oneOf":[{"type":"object","required":["files"],"properties":{"files":{"type":"array","minItems":1,"maxItems":64,"items":{"$ref":"#/components/schemas/WorkflowFile"}}},"additionalProperties":false},{"type":"object","required":["artifact_id"],"properties":{"artifact_id":{"type":"string","format":"uuid"}},"additionalProperties":false}]},"WorkflowCreateRequest":{"type":"object","required":["source"],"properties":{"source":{"$ref":"#/components/schemas/WorkflowSource"},"idempotency_key":{"type":"string","minLength":1,"maxLength":200}},"additionalProperties":false},"WorkflowRunRequest":{"type":"object","required":["version","mode","max_charge_credits","idempotency_key"],"properties":{"version":{"type":"integer","minimum":1},"input":{"type":"object","additionalProperties":true},"input_artifact_id":{"type":"string","format":"uuid"},"mode":{"type":"string","enum":["pilot","run"]},"max_charge_credits":{"$ref":"#/components/schemas/DecimalString"},"max_rows":{"type":"integer","minimum":1,"maximum":10000},"idempotency_key":{"type":"string","minLength":1,"maxLength":200}},"additionalProperties":false},"OkibiLinkedAccount":{"type":"object","additionalProperties":false,"required":["email","passwordSetupPending"],"description":"The Locus user behind the Okibi identity link. Locus provisions an account for an Okibi-verified email that has none; that account keeps a managed password until the person sets one through the emailed link or the dashboard's first screen.","properties":{"email":{"type":"string","format":"email"},"passwordSetupPending":{"type":"boolean","description":"True while the provisioned account still has to choose a password. Tell the user to check their email for the Locus set-password link."}}},"OkibiCliConnectionTools":{"type":"object","additionalProperties":false,"required":["enable"],"properties":{"enable":{"oneOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Provider/endpoint slugs this credential may call. null means every endpoint the workspace has enabled."}}},"OkibiCliConnectionMetadata":{"type":"object","additionalProperties":false,"required":["id","status","keyPrefix","tools","expiresAt","lastUsedAt"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["active","expired","revoked"]},"keyPrefix":{"type":"string","description":"Non-secret display prefix."},"tools":{"$ref":"#/components/schemas/OkibiCliConnectionTools"},"expiresAt":{"type":"string","format":"date-time","description":"Moves forward on each authenticated use, to 7 days after that use and never past 30 days after issue."},"lastUsedAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]}}},"OkibiCliCredentialEnvelope":{"type":"object","additionalProperties":false,"required":["success","created","rotated","account","connection","storage"],"properties":{"success":{"const":true},"created":{"type":"boolean","description":"True when this bootstrap created the installation's credential (HTTP 201)."},"rotated":{"type":"boolean","description":"True when a new registration token replaced the existing credential's secret in place (HTTP 200)."},"account":{"$ref":"#/components/schemas/OkibiLinkedAccount"},"connection":{"type":"object","additionalProperties":false,"required":["id","status","keyPrefix","tools","expiresAt","lastUsedAt","credential"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["active","expired","revoked"]},"keyPrefix":{"type":"string","description":"Non-secret display prefix."},"tools":{"$ref":"#/components/schemas/OkibiCliConnectionTools"},"expiresAt":{"type":"string","format":"date-time","description":"Moves forward on each authenticated use, to 7 days after that use and never past 30 days after issue."},"lastUsedAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"credential":{"type":"string","pattern":"^lcac_","readOnly":true,"description":"Raw scoped Locus credential. Capture once and never log it."}}},"storage":{"type":"object","additionalProperties":false,"required":["environmentVariable","instruction"],"properties":{"environmentVariable":{"const":"LOCUS_SECRET_KEY"},"instruction":{"type":"string"}}}}},"AgentRegistrationToken":{"type":"string","pattern":"^[A-Za-z0-9_-]{32}$","description":"Canonical base64url encoding of 24 bytes generated by a cryptographically secure random-number generator."},"AgentNativeRegistrationRequest":{"type":"object","additionalProperties":false,"required":["name","registrationToken"],"properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Control and bidirectional-formatting characters are rejected."},"registrationToken":{"$ref":"#/components/schemas/AgentRegistrationToken"},"agentEmail":{"type":"string","format":"email","maxLength":320,"description":"Optional AgentID inbox sent as login_hint. The verified token claim is authoritative."}}},"AgentEmailSignupRequest":{"type":"object","additionalProperties":false,"required":["email","name","registrationToken"],"properties":{"email":{"type":"string","format":"email","maxLength":320,"description":"The human owner's address. It receives a one-time claim link and is not treated as verified until the link is opened."},"name":{"type":"string","minLength":1,"maxLength":100,"description":"Agent and workspace name. Control and bidirectional-formatting characters are rejected."},"registrationToken":{"$ref":"#/components/schemas/AgentRegistrationToken"}}},"AgentClaimTokenRequest":{"type":"object","additionalProperties":false,"required":["token"],"properties":{"token":{"type":"string","pattern":"^lcclm_[A-Za-z0-9_-]{43}$","description":"Read from the claim email URL fragment; never sent in a URL."}}},"AgentClaimDecisionRequest":{"type":"object","additionalProperties":false,"required":["token","workspaceIds"],"properties":{"token":{"type":"string","pattern":"^lcclm_[A-Za-z0-9_-]{43}$","description":"Read from the claim email URL fragment; never sent in a URL."},"workspaceIds":{"type":"array","minItems":1,"maxItems":100,"uniqueItems":true,"items":{"type":"string","format":"uuid"},"description":"The workspaces from preview that the person chose."}}},"AgentSignupPending":{"type":"object","additionalProperties":false,"required":["onboardingState","registration","nextAction","activated"],"properties":{"onboardingState":{"const":"identity_required"},"registration":{"type":"object","additionalProperties":false,"required":["id","provider","status","authorizationUrl","expiresAt","pollAfterMs"],"properties":{"id":{"type":"string","format":"uuid"},"provider":{"const":"agentid"},"status":{"type":"string","enum":["pending","verified"]},"authorizationUrl":{"type":"string","format":"uri"},"expiresAt":{"type":"string","format":"date-time"},"pollAfterMs":{"type":"integer","minimum":1000}}},"nextAction":{"type":"object","additionalProperties":true},"activated":{"const":false}}},"AgentSignupPendingEnvelope":{"type":"object","additionalProperties":false,"required":["success","account"],"properties":{"success":{"const":true},"account":{"$ref":"#/components/schemas/AgentSignupPending"}}},"AgentOwnedBalance":{"type":"object","additionalProperties":false,"required":["usd","credits","creditsPerDollar"],"properties":{"usd":{"$ref":"#/components/schemas/DecimalString"},"credits":{"$ref":"#/components/schemas/DecimalString"},"creditsPerDollar":{"type":"string","pattern":"^\\d+$"}}},"AgentOwnedAccount":{"type":"object","required":["id","name","status","onboardingState","balance","connection","identity","mcp","links","nextAction","activated"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"onboardingState":{"type":"string","enum":["funding_required","ready"]},"balance":{"$ref":"#/components/schemas/AgentOwnedBalance"},"connection":{"type":"object","additionalProperties":false,"required":["id","keyPrefix","expiresAt"],"properties":{"id":{"type":"string","format":"uuid"},"keyPrefix":{"type":"string","pattern":"^lcac_"},"expiresAt":{"type":"string","format":"date-time"},"credential":{"type":"string","pattern":"^lcac_","description":"Returned on registration replay and rotation. Store immediately."}}},"identity":{"type":"object","additionalProperties":false,"required":["provider","email"],"properties":{"provider":{"const":"agentid"},"email":{"type":"string","format":"email"}}},"mcp":{"type":"object","additionalProperties":true},"links":{"type":"object","additionalProperties":{"type":"string","format":"uri"}},"nextAction":{"type":"object","additionalProperties":true},"created":{"type":"boolean"},"credentialRenewed":{"type":"boolean"},"credentialRecovered":{"type":"boolean"},"activated":{"const":true}}},"AgentOwnedAccountEnvelope":{"type":"object","additionalProperties":false,"required":["success","account"],"properties":{"success":{"const":true},"account":{"$ref":"#/components/schemas/AgentOwnedAccount"}}},"AgentFundingState":{"type":"string","enum":["awaiting_payment","processing","ready","expired","failed"]},"AgentFundingQuote":{"type":"object","additionalProperties":false,"required":["feeMode","creditsUsd","credits","feeUsd","totalUsd"],"properties":{"feeMode":{"type":"string","enum":["pass_through","absorb"]},"creditsUsd":{"$ref":"#/components/schemas/DecimalString"},"credits":{"$ref":"#/components/schemas/DecimalString"},"feeUsd":{"$ref":"#/components/schemas/DecimalString"},"totalUsd":{"$ref":"#/components/schemas/DecimalString"}}},"AgentFundingSession":{"type":"object","additionalProperties":false,"required":["success","fundingSessionId","checkoutUrl","statusUrl","expiresAt","quote","humanHandoff","pollAfterMs"],"properties":{"success":{"const":true},"fundingSessionId":{"type":"string","pattern":"^cs_"},"checkoutUrl":{"type":"string","format":"uri","description":"Share only this Stripe-hosted URL with the human payer."},"statusUrl":{"type":"string","format":"uri"},"expiresAt":{"type":["string","null"],"format":"date-time"},"quote":{"$ref":"#/components/schemas/AgentFundingQuote"},"humanHandoff":{"type":"object","additionalProperties":false,"required":["message","instruction"],"properties":{"message":{"type":"string"},"instruction":{"type":"string"}}},"pollAfterMs":{"type":"integer","minimum":1000}}},"AgentFundingStatus":{"type":"object","additionalProperties":false,"required":["success","fundingSessionId","state","paymentStatus","balance","nextAction"],"properties":{"success":{"const":true},"fundingSessionId":{"type":"string","pattern":"^cs_"},"state":{"$ref":"#/components/schemas/AgentFundingState"},"paymentStatus":{"type":"string"},"balance":{"$ref":"#/components/schemas/AgentOwnedBalance"},"nextAction":{"type":"object","additionalProperties":true}}},"AgentFundingPublicStatus":{"type":"object","additionalProperties":false,"required":["success","funding"],"properties":{"success":{"const":true},"funding":{"type":"object","additionalProperties":false,"required":["state","agentName","creditsUsd","credits"],"properties":{"state":{"$ref":"#/components/schemas/AgentFundingState"},"agentName":{"type":"string"},"creditsUsd":{"$ref":"#/components/schemas/DecimalString"},"credits":{"$ref":"#/components/schemas/DecimalString"}}}}},"WorkspaceSpendLimitDenial":{"type":"object","description":"Terminal denial returned when a burn would push the workspace past its monthly spend ceiling. Do not retry before resetsAt: the ceiling is a workspace setting, not a transient condition, and the call was never dispatched so no credits moved.","additionalProperties":false,"required":["error","code","message","limitUsd","committedUsd","requestedUsd","resetsAt","apiCallId"],"properties":{"success":{"const":false,"description":"Present on external-rail denials and absent on hosted-provider denials. Match on `code`, not on this field."},"error":{"const":"Workspace monthly spend limit reached"},"code":{"const":"TENANT_MONTHLY_SPEND_LIMIT_EXCEEDED"},"message":{"type":"string"},"limitUsd":{"$ref":"#/components/schemas/DecimalString"},"committedUsd":{"$ref":"#/components/schemas/DecimalString","description":"Captured plus in-flight spend already counted against the ceiling."},"requestedUsd":{"$ref":"#/components/schemas/DecimalString","description":"What this call would have added."},"resetsAt":{"type":"string","format":"date-time","description":"When the window rolls over and burns resume. Raising monthlyLimitUsd also clears the denial immediately."},"apiCallId":{"type":"string","format":"uuid"}}},"WorkspaceSpendControls":{"type":"object","description":"Account-wide monthly spend controls and low-balance notification state, plus the live position in the current UTC month window. Available to Personal and enterprise accounts. Amounts are exact USD decimal strings.","additionalProperties":false,"required":["periodStart","periodEnd","spentUsd","pendingUsd","committedUsd","remainingUsd","monthlyLimitUsd","alertThresholdUsd","lowBalanceAlertUsd","lowBalanceAlertSentAt","hardLimitReached","alert"],"properties":{"periodStart":{"type":"string","format":"date-time","description":"Start of the current UTC calendar-month window."},"periodEnd":{"type":"string","format":"date-time","description":"When the window resets."},"spentUsd":{"allOf":[{"$ref":"#/components/schemas/DecimalString"}],"description":"Captured spend in this window."},"pendingUsd":{"allOf":[{"$ref":"#/components/schemas/DecimalString"}],"description":"Held but not yet captured (in-flight calls)."},"committedUsd":{"allOf":[{"$ref":"#/components/schemas/DecimalString"}],"description":"spentUsd plus pendingUsd — the figure checked against the limit."},"remainingUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}],"description":"null when no monthly limit is set."},"monthlyLimitUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}],"description":"Hard ceiling. null means unlimited."},"alertThresholdUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}],"description":"Monthly spend email trigger. null means no alert."},"lowBalanceAlertUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}],"description":"Remaining prepaid-balance email trigger. null means no alert."},"lowBalanceAlertSentAt":{"type":["string","null"],"format":"date-time","description":"When the current low-balance crossing was emailed. null while armed; it returns to null after the balance recovers above the threshold."},"hardLimitReached":{"type":"boolean","description":"true once committedUsd reaches monthlyLimitUsd. Further burns are denied with TENANT_MONTHLY_SPEND_LIMIT_EXCEEDED until the window resets."},"alert":{"type":"object","additionalProperties":false,"required":["status","triggeredAt","sentAt","lastError"],"properties":{"status":{"type":["string","null"],"enum":["pending","sent","failed",null]},"triggeredAt":{"type":["string","null"],"format":"date-time"},"sentAt":{"type":["string","null"],"format":"date-time"},"lastError":{"type":["string","null"]}}}}},"PricingExplain":{"type":"object","description":"The base-cost to effective-price translation for one endpoint, including which configuration level supplied each markup. Money fields are exact decimal strings, and are null for endpoints priced live per call.","additionalProperties":false,"required":["provider","endpoint","slug","method","dynamic","estimated","enabled","creditsPerDollar","markupBps","markupSource","flatSource","overridden","baseUsd","baseCredits","markupUsd","flatMarkupUsd","marginUsd","marginCredits","effectiveUsd","effectiveCredits","humanSummary"],"properties":{"provider":{"type":"string"},"endpoint":{"type":"string"},"slug":{"type":"string","description":"provider/endpoint"},"method":{"type":"string","description":"Upstream HTTP method."},"dynamic":{"type":"boolean","description":"true when the endpoint is metered and priced per call."},"estimated":{"type":"boolean","description":"true when baseUsd is an estimate rather than a fixed price."},"enabled":{"type":"boolean"},"creditsPerDollar":{"type":"integer"},"markupBps":{"type":"integer"},"markupSource":{"type":"string","enum":["endpoint","provider","global"]},"flatSource":{"type":"string","enum":["endpoint","provider","global"]},"overridden":{"type":"boolean","description":"true when either markup comes from a provider or endpoint override rather than the tenant default."},"baseUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"baseCredits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"markupUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}],"description":"Percentage portion: base times bps/10000, ceiling at 6dp."},"flatMarkupUsd":{"allOf":[{"$ref":"#/components/schemas/DecimalString"}]},"marginUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"marginCredits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"effectiveUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"effectiveCredits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"humanSummary":{"type":"string","description":"One-sentence plain-language explanation of the price."}}},"CredentialAuditEvent":{"type":"object","description":"One credential-lifecycle event. Raw credentials and key hashes are never included.","additionalProperties":false,"required":["id","credentialType","credentialId","action","actorType","actorId","metadata","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"credentialType":{"type":"string","description":"Which credential family the event describes, for example api_key, agent_connection, end_user_token, or webhook_secret."},"credentialId":{"type":["string","null"]},"action":{"type":"string","description":"issued, rotated, or revoked."},"actorType":{"type":"string","description":"Whether a signed-in member, a secret key, or the system performed it."},"actorId":{"type":["string","null"]},"metadata":{"type":["object","null"],"additionalProperties":true},"createdAt":{"type":"string","format":"date-time"}}},"CatalogChange":{"type":"object","description":"One catalog enablement change. Endpoint rows carry the effective state before and after; provider rows carry the provider row's own override (null before means no override existed).","additionalProperties":false,"required":["id","slug","scope","enabledBefore","enabledAfter","actor","via","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","description":"A provider id or provider/endpoint."},"scope":{"type":"string","enum":["provider","endpoint"]},"enabledBefore":{"type":["boolean","null"]},"enabledAfter":{"type":"boolean"},"actor":{"type":"object","required":["type","id","label"],"properties":{"type":{"type":"string","enum":["member","credential","agent","system"]},"id":{"type":["string","null"],"description":"The member's subject, the key's id, or the agent connection's id."},"label":{"type":"string","description":"What to show: a member's email, a key's name, an agent connection's name, or a fixed name when nothing better is known."}},"additionalProperties":false},"via":{"type":"string","enum":["dashboard","onboarding","api","agent","credential","cli","router","batch","system"]},"createdAt":{"type":"string","format":"date-time"}}},"SecurityAuditEvent":{"type":"object","description":"One sensitive-mutation audit row, written before the success response and fail-closed if the audit write fails. Submitted credentials are redacted inside beforeState and afterState.","additionalProperties":false,"required":["id","action","resourceType","actorType","authMethod","requestId","outcome","httpStatus","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"tenantId":{"type":"string","format":"uuid"},"action":{"type":"string"},"resourceType":{"type":"string"},"resourceId":{"type":["string","null"]},"actorType":{"type":"string"},"actorId":{"type":["string","null"]},"authMethod":{"type":"string"},"requestId":{"type":"string"},"sourceIp":{"type":["string","null"]},"outcome":{"type":"string"},"httpStatus":{"type":"integer"},"beforeState":{"type":["object","null"],"additionalProperties":true},"afterState":{"type":["object","null"],"additionalProperties":true},"errorCode":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}}},"EndUserTokenRecord":{"type":"object","description":"Metadata for one minted end-user token. The token itself is returned only at mint time and is never recoverable.","additionalProperties":false,"required":["id","signingKeyId","status","expiresAt","revokedAt","revokedReason","lastUsedAt","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"signingKeyId":{"type":"string","description":"kid of the RS256 key that signed it, resolvable through the public JWKS."},"status":{"type":"string","enum":["active","expired","revoked"],"description":"Reported as expired as soon as expiresAt has passed, without waiting for a sweep."},"expiresAt":{"type":"string","format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"},"revokedReason":{"type":["string","null"]},"lastUsedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}},"StripeConnectStatus":{"type":"object","description":"Stripe Connect linkage for margin payouts.","additionalProperties":false,"required":["configured","connected","accountId","payoutMethod","payoutsEnabled"],"properties":{"configured":{"type":"boolean","description":"false when this deployment has no Connect application configured."},"connected":{"type":"boolean"},"accountId":{"type":["string","null"],"description":"The tenant's own Stripe account id."},"payoutMethod":{"type":"string","enum":["usdc","stripe"]},"payoutsEnabled":{"type":["boolean","null"],"description":"Live capability read from Stripe. null when the account is unreachable or not linked."}}},"InsufficientScopeError":{"type":"object","additionalProperties":false,"required":["success","error","code","message","requiredScopes","presentScopes"],"properties":{"success":{"const":false},"error":{"const":"Forbidden"},"code":{"const":"INSUFFICIENT_SCOPE"},"message":{"type":"string"},"requiredScopes":{"type":"array","items":{"$ref":"#/components/schemas/CreditsTenantScope"},"minItems":1,"uniqueItems":true},"presentScopes":{"type":"array","items":{"$ref":"#/components/schemas/CreditsTenantScope"},"uniqueItems":true}}},"CredentialPriceOverride":{"type":"object","additionalProperties":false,"properties":{"markupBps":{"type":"integer","minimum":0,"maximum":10000},"flatMarkupUsdc":{"$ref":"#/components/schemas/DecimalString"}},"minProperties":1},"CredentialPricingPolicy":{"type":"object","additionalProperties":false,"properties":{"markupBps":{"type":"integer","minimum":0,"maximum":10000},"flatMarkupUsdc":{"$ref":"#/components/schemas/DecimalString"},"endpoints":{"type":"object","maxProperties":1000,"additionalProperties":{"$ref":"#/components/schemas/CredentialPriceOverride"}}},"minProperties":1},"ApiKeyCreateRequest":{"type":"object","additionalProperties":false,"required":["kind"],"properties":{"kind":{"type":"string","enum":["secret","publishable","sandbox"]},"name":{"type":"string","minLength":1,"maxLength":100},"scopes":{"type":"array","items":{"$ref":"#/components/schemas/CreditsTenantScope"},"uniqueItems":true},"tools":{"type":"object","additionalProperties":false,"required":["enable"],"properties":{"enable":{"type":"array","maxItems":1000,"items":{"type":"string","pattern":"^[^/]+/[^/]+$"},"uniqueItems":true}}},"pricing":{"$ref":"#/components/schemas/CredentialPricingPolicy"},"expiresIn":{"type":"integer","minimum":60,"maximum":31536000}}},"AgentConnectionCreateRequest":{"type":"object","additionalProperties":false,"required":["name","mode"],"properties":{"name":{"type":"string","minLength":1,"maxLength":100},"mode":{"type":"string","enum":["platform","end_user"]},"externalUserId":{"$ref":"#/components/schemas/ExternalUserId"},"tools":{"type":"object","additionalProperties":false,"properties":{"enable":{"type":"array","maxItems":1000,"items":{"type":"string","pattern":"^[^/]+/[^/]+$"},"uniqueItems":true}}},"pricing":{"$ref":"#/components/schemas/CredentialPricingPolicy"},"maxCreditsPerCall":{"$ref":"#/components/schemas/DecimalString"},"maxCreditsPerLoop":{"$ref":"#/components/schemas/DecimalString"},"expiresInSeconds":{"type":"integer","minimum":300,"maximum":31536000}}},"AgentConnection":{"type":"object","required":["id","name","status","mode","keyPrefix","expiresAt","createdAt","updatedAt","mcp"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["active","expired","revoked"]},"mode":{"type":"string","enum":["platform","end_user"]},"externalUserId":{"oneOf":[{"$ref":"#/components/schemas/ExternalUserId"},{"type":"null"}]},"tools":{"type":"object","properties":{"enable":{"type":["array","null"],"items":{"type":"string"}}}},"pricing":{"oneOf":[{"$ref":"#/components/schemas/CredentialPricingPolicy"},{"type":"null"}]},"maxCreditsPerCall":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"maxCreditsPerLoop":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"keyPrefix":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"},"rotatedAt":{"type":["string","null"],"format":"date-time"},"lastUsedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"mcp":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"headers":{"type":"object","additionalProperties":{"type":"string"}}}},"credential":{"type":"string","description":"Present only in create/rotate responses and shown once"}}},"AgentConnectionEnvelope":{"type":"object","additionalProperties":false,"required":["success","connection"],"properties":{"success":{"const":true},"connection":{"$ref":"#/components/schemas/AgentConnection"}}},"UnknownTenantFieldsError":{"type":"object","additionalProperties":false,"required":["success","error","code","fields","message"],"properties":{"success":{"const":false},"error":{"const":"Bad Request"},"code":{"const":"unknown_fields"},"fields":{"type":"array","items":{"type":"string"},"minItems":1,"uniqueItems":true},"message":{"type":"string"}}},"CreditsTenantScope":{"type":"string","enum":["tenant:read","tenant:write","catalog:write","credits:move","credentials:manage","tokens:manage","payouts:manage","members:manage","widget:read"]},"WorkspaceRole":{"type":"string","description":"Owner and admin are workspace-administrator roles. Exactly one member holds owner; it moves only through the transfer-ownership operation, never through role updates or invitations.","enum":["owner","admin","developer","billing","viewer"]},"InvitableWorkspaceRole":{"type":"string","enum":["admin","developer","billing","viewer"]},"WorkspaceMembership":{"type":"object","additionalProperties":false,"required":["tenantId","tenantName","tenantStatus","role"],"properties":{"tenantId":{"type":"string","format":"uuid"},"tenantName":{"type":"string"},"tenantStatus":{"type":"string","enum":["active","suspended"]},"role":{"$ref":"#/components/schemas/WorkspaceRole"}}},"WorkspaceMember":{"type":"object","additionalProperties":false,"required":["id","email","role","cognitoSub","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"role":{"$ref":"#/components/schemas/WorkspaceRole"},"cognitoSub":{"type":"string","description":"Cognito subject usage is attributed to; the identity analytics keys member spend by."},"createdAt":{"type":"string","format":"date-time"}}},"WorkspaceInvitation":{"type":"object","additionalProperties":false,"required":["id","email","role","status","deliveryStatus","expiresAt","deliveryAttempts","lastDeliveryError","lastSentAt","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"role":{"$ref":"#/components/schemas/InvitableWorkspaceRole"},"status":{"type":"string","enum":["PENDING","PROVISIONING"]},"deliveryStatus":{"type":"string","enum":["QUEUED","SENT","FAILED"]},"expiresAt":{"type":"string","format":"date-time"},"deliveryAttempts":{"type":"integer","minimum":0},"lastDeliveryError":{"type":["string","null"]},"lastSentAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}},"WorkspaceInvitationPreview":{"type":"object","additionalProperties":false,"required":["id","emailMasked","workspaceName","role","status","expiresAt"],"properties":{"id":{"type":"string","format":"uuid"},"emailMasked":{"type":"string"},"workspaceName":{"type":"string"},"role":{"$ref":"#/components/schemas/InvitableWorkspaceRole"},"status":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"}}},"ExternalUserId":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9][A-Za-z0-9._:@/-]{0,199}$","description":"Case-sensitive immutable ID in the tenant namespace. Prefer an identity-provider subject, not an email address."},"EndUserTokenRequest":{"type":"object","properties":{"expiresIn":{"type":"integer","minimum":60,"maximum":3600,"default":3600},"sessionId":{"type":"string","minLength":16,"maxLength":128,"pattern":"^[A-Za-z0-9][A-Za-z0-9._:-]{15,127}$","description":"High-entropy binding value. The JWT stores only its SHA-256 fingerprint; send the raw value as X-Locus-Session-Id."}},"additionalProperties":false},"EndUserTokenResponse":{"type":"object","required":["success","token","expiresAt","expiresIn","tokenId","externalUserId"],"properties":{"success":{"const":true},"token":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"},"expiresIn":{"type":"integer","minimum":60,"maximum":3600},"tokenId":{"type":"string","format":"uuid"},"externalUserId":{"$ref":"#/components/schemas/ExternalUserId"}},"additionalProperties":false},"DecimalString":{"type":"string","pattern":"^\\d+(?:\\.\\d{1,6})?$","description":"Non-negative exact decimal string with at most six fractional digits. Endpoint-specific positivity and amount limits still apply."},"InferenceModelCapabilities":{"type":"object","required":["text","vision","tools","json","streaming","reasoning"],"properties":{"text":{"type":"boolean"},"vision":{"type":"boolean"},"tools":{"type":"boolean"},"json":{"type":"boolean"},"streaming":{"type":"boolean","description":"Capability of the current Locus credits route, not only the upstream model."},"reasoning":{"type":"boolean"}},"additionalProperties":false},"InferenceModelMetadata":{"type":"object","required":["id","status","deprecationDate","contextWindowTokens","providerMaxOutputTokens","locusMaxOutputTokens","recommendedMinOutputTokens","pricing","capabilities","request"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["active","deprecated"]},"deprecationDate":{"type":["string","null"],"format":"date"},"contextWindowTokens":{"type":"integer","minimum":1},"providerMaxOutputTokens":{"type":"integer","minimum":1},"locusMaxOutputTokens":{"type":"integer","minimum":1},"recommendedMinOutputTokens":{"type":"integer","minimum":1},"pricing":{"type":"object","required":["unit","input","output"],"properties":{"unit":{"const":"usd_per_1m_tokens"},"input":{"type":"string","pattern":"^\\d+(?:\\.\\d+)?$"},"output":{"type":"string","pattern":"^\\d+(?:\\.\\d+)?$"}},"additionalProperties":false},"capabilities":{"$ref":"#/components/schemas/InferenceModelCapabilities"},"request":{"type":"object","required":["outputTokenField","incompatibleFields"],"properties":{"outputTokenField":{"type":"string","enum":["max_tokens","max_completion_tokens"]},"incompatibleFields":{"type":"array","items":{"type":"string"},"uniqueItems":true}},"additionalProperties":false}},"additionalProperties":false},"InferenceModelCatalog":{"type":"object","required":["schemaVersion","pricingVersion","provider","publishedAt","freshness","models"],"properties":{"schemaVersion":{"const":"2026-08-01"},"pricingVersion":{"type":"string"},"provider":{"type":"string"},"publishedAt":{"type":"string","format":"date-time"},"freshness":{"type":"object","required":["maxAgeSeconds","staleAfter","source"],"properties":{"maxAgeSeconds":{"type":"integer","minimum":0},"staleAfter":{"type":"string","format":"date-time"},"source":{"const":"locus-reviewed-static"}},"additionalProperties":false},"models":{"type":"array","items":{"$ref":"#/components/schemas/InferenceModelMetadata"}}},"additionalProperties":false},"ModelCatalogResponse":{"type":"object","required":["success","catalog"],"properties":{"success":{"const":true},"catalog":{"$ref":"#/components/schemas/InferenceModelCatalog"}},"additionalProperties":false},"SafeUpstreamValidationDetail":{"type":"object","properties":{"type":{"type":"string","maxLength":128},"code":{"type":"string","maxLength":128},"param":{"type":"string","maxLength":256},"message":{"type":"string","maxLength":1024},"errors":{"type":"array","maxItems":20,"description":"Fal field errors, with the first error also exposed in the top-level fields. Echoed input and internal context are omitted.","items":{"type":"object","properties":{"type":{"type":"string","maxLength":128},"param":{"type":"string","maxLength":256},"message":{"type":"string","maxLength":1024}},"additionalProperties":false}}},"additionalProperties":false},"UpstreamWrapperError":{"type":"object","required":["success","error","code","upstreamStatus","apiCallId"],"properties":{"success":{"const":false},"error":{"const":"Upstream API call failed"},"code":{"const":"upstream_validation_error"},"upstreamStatus":{"type":"integer","enum":[400,422]},"validation":{"$ref":"#/components/schemas/SafeUpstreamValidationDetail"},"apiCallId":{"type":"string"}},"additionalProperties":false},"McpJsonRpcRequest":{"type":"object","required":["jsonrpc","method"],"properties":{"jsonrpc":{"const":"2.0"},"id":{"type":["string","number","null"]},"method":{"type":"string","examples":["initialize","tools/list","tools/call","resources/read","prompts/get"]},"params":{"type":"object","additionalProperties":true}},"additionalProperties":false},"McpJsonRpcSuccess":{"type":"object","required":["jsonrpc","id","result"],"properties":{"jsonrpc":{"const":"2.0"},"id":{"type":["string","number","null"]},"result":{"anyOf":[{"$ref":"#/components/schemas/McpToolCallResult"},{"type":"object","additionalProperties":true}]}},"additionalProperties":false},"McpJsonRpcError":{"type":"object","required":["jsonrpc","id","error"],"properties":{"jsonrpc":{"const":"2.0"},"id":{"type":["string","number","null"]},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","description":"JSON-RPC/MCP protocol code, not a Locus billing status."},"message":{"type":"string"},"data":{}},"additionalProperties":false}},"additionalProperties":false},"McpToolCallResult":{"type":"object","required":["content"],"description":"Success and application-failure result for tools/call. isError=true is failure even though the JSON-RPC promise resolved.","properties":{"content":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/McpTextContent"},{"$ref":"#/components/schemas/McpImageContent"},{"$ref":"#/components/schemas/McpAudioContent"},{"$ref":"#/components/schemas/McpEmbeddedResource"}]}},"isError":{"type":"boolean","default":false},"structuredContent":{"type":"object","additionalProperties":true,"description":"Typed success data and compact artifact/billing descriptors. Raw binary or oversized JSON is not duplicated here."},"_meta":{"$ref":"#/components/schemas/McpLocusMeta"}},"additionalProperties":false},"McpTextContent":{"type":"object","required":["type","text"],"properties":{"type":{"const":"text"},"text":{"type":"string","description":"JSON for normal results. When isError=true, parse this as McpToolErrorBody."}},"additionalProperties":true},"McpImageContent":{"type":"object","required":["type","data","mimeType"],"properties":{"type":{"const":"image"},"data":{"type":"string","contentEncoding":"base64"},"mimeType":{"type":"string","pattern":"^image/"}},"additionalProperties":true},"McpAudioContent":{"type":"object","required":["type","data","mimeType"],"properties":{"type":{"const":"audio"},"data":{"type":"string","contentEncoding":"base64"},"mimeType":{"type":"string","pattern":"^audio/"}},"additionalProperties":true},"McpEmbeddedResource":{"type":"object","required":["type","resource"],"properties":{"type":{"const":"resource"},"resource":{"type":"object","required":["uri"],"properties":{"uri":{"type":"string"},"mimeType":{"type":"string"},"text":{"type":"string"},"blob":{"type":"string","contentEncoding":"base64"}},"additionalProperties":true}},"additionalProperties":true},"McpLocusMeta":{"type":"object","properties":{"locus/status":{"type":"integer","minimum":100,"maximum":599},"locus/creditsCharged":{"$ref":"#/components/schemas/DecimalString"},"locus/creditsBalance":{"$ref":"#/components/schemas/DecimalString"},"locus/costUsd":{"$ref":"#/components/schemas/DecimalString","description":"Base USD cost; secret-key principals only."},"locus/idempotencyKey":{"type":"string"},"locus/approvalId":{"type":"string","format":"uuid"},"locus/maxChargeCredits":{"$ref":"#/components/schemas/DecimalString"},"locus/reapprovalRequired":{"type":"boolean"},"locus/artifact":{"$ref":"#/components/schemas/McpArtifact"},"locus/presentation":{"$ref":"#/components/schemas/McpPresentation"}},"additionalProperties":true},"McpToolErrorBody":{"type":"object","required":["failureClass","retryable","safeToRetry","idempotencyStatus","hint"],"properties":{"error":{"type":"string"},"code":{"type":"string","examples":["charge_ceiling_exceeded","approval_expired"]},"message":{"type":"string"},"failureClass":{"type":"string","enum":["validation","insufficient_credits","authorization","discovery","approval_or_idempotency","rate_limit","upstream_or_transport","request"]},"retryable":{"type":"boolean"},"safeToRetry":{"type":"boolean","description":"True only when retrying with the same idempotency key is safe and useful."},"retryAfter":{"type":"integer","minimum":1,"description":"Whole seconds to wait before retrying a rate-limited call."},"idempotencyStatus":{"const":"protected"},"refunded":{"type":"boolean","description":"Present for upstream/transport failures; the caller was not charged or its reservation was released."},"hint":{"type":"string"},"requiredCredits":{"$ref":"#/components/schemas/DecimalString"},"availableCredits":{"$ref":"#/components/schemas/DecimalString"},"maxChargeCredits":{"$ref":"#/components/schemas/DecimalString"},"currentChargeCredits":{"$ref":"#/components/schemas/DecimalString"},"alternatives":{"type":"array","items":{"$ref":"#/components/schemas/McpAlternative"}}},"additionalProperties":true},"McpAlternative":{"type":"object","required":["slug","capabilityMatch","expectedCredits","requiresReapproval"],"properties":{"slug":{"type":"string"},"capabilityMatch":{"type":"string"},"expectedCredits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"const":"variable"}]},"requiresReapproval":{"const":true}},"additionalProperties":false},"McpArtifact":{"type":"object","required":["uri","mime_type","byte_size","sha256","filename","disposition","expires_at"],"properties":{"uri":{"type":"string","pattern":"^urn:locus:artifact:sha256:"},"mime_type":{"type":"string"},"byte_size":{"type":"integer","minimum":0},"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$"},"filename":{"type":"string"},"disposition":{"const":"inline"},"expires_at":{"type":["string","null"],"format":"date-time"},"download_url":{"type":"string","format":"uri","description":"Signed link to the bytes. No bearer needed; it expires at expires_at."},"api_call_id":{"type":"string"}},"additionalProperties":false},"McpPresentation":{"type":"object","required":["providerName","actionName","category","description","logoUrl","fallback","assetVersion","cacheControl","presentationOnly"],"properties":{"providerName":{"type":"string"},"actionName":{"type":"string"},"category":{"type":["string","null"]},"description":{"type":"string"},"logoUrl":{"type":["string","null"],"format":"uri"},"fallback":{"type":"object","required":["type","text"],"properties":{"type":{"const":"monogram"},"text":{"type":"string","minLength":1}},"additionalProperties":false,"description":"Stable monogram used when logoUrl is absent or fails."},"assetVersion":{"const":"1","description":"Version token used in Locus-hosted logo URLs for cache invalidation."},"cacheControl":{"const":"public, max-age=86400"},"presentationOnly":{"const":true}},"additionalProperties":false},"TopupAmount":{"oneOf":[{"type":"object","required":["usd"],"not":{"required":["credits"]},"properties":{"usd":{"$ref":"#/components/schemas/DecimalString"}}},{"type":"object","required":["credits"],"not":{"required":["usd"]},"properties":{"credits":{"$ref":"#/components/schemas/DecimalString"}}}]},"AgentFundingAmount":{"oneOf":[{"type":"object","required":["usd"],"not":{"required":["credits"]},"properties":{"usd":{"$ref":"#/components/schemas/DecimalString"}},"additionalProperties":false},{"type":"object","required":["credits"],"not":{"required":["usd"]},"properties":{"credits":{"$ref":"#/components/schemas/DecimalString"}},"additionalProperties":false}]},"TopupMetadata":{"type":"object","maxProperties":16,"propertyNames":{"pattern":"^[A-Za-z0-9][A-Za-z0-9_.-]{0,39}$"},"additionalProperties":{"type":"string","maxLength":256},"description":"Serialized object is limited to 500 characters."},"TopupSelfRequest":{"allOf":[{"$ref":"#/components/schemas/TopupAmount"},{"type":"object","required":["successUrl","cancelUrl"],"properties":{"usd":{"$ref":"#/components/schemas/DecimalString"},"credits":{"$ref":"#/components/schemas/DecimalString"},"successUrl":{"type":"string","format":"uri","maxLength":2048},"cancelUrl":{"type":"string","format":"uri","maxLength":2048},"metadata":{"$ref":"#/components/schemas/TopupMetadata"}},"unevaluatedProperties":false}]},"TopupRequest":{"allOf":[{"$ref":"#/components/schemas/TopupAmount"},{"type":"object","required":["successUrl","cancelUrl"],"properties":{"usd":{"$ref":"#/components/schemas/DecimalString"},"credits":{"$ref":"#/components/schemas/DecimalString"},"successUrl":{"type":"string","format":"uri","maxLength":2048},"cancelUrl":{"type":"string","format":"uri","maxLength":2048},"externalUserId":{"$ref":"#/components/schemas/ExternalUserId"},"metadata":{"$ref":"#/components/schemas/TopupMetadata"}},"unevaluatedProperties":false}]},"TopupQuoteRequest":{"description":"Quote pricing for a hypothetical top-up. Declare externalUserId when the eventual create targets an end user, so the quote's bonus fields match what the create will actually grant (end-user top-ups never earn a volume bonus).","allOf":[{"$ref":"#/components/schemas/TopupAmount"},{"type":"object","properties":{"usd":{"$ref":"#/components/schemas/DecimalString"},"credits":{"$ref":"#/components/schemas/DecimalString"},"externalUserId":{"$ref":"#/components/schemas/ExternalUserId"}},"unevaluatedProperties":false}]},"TopupQuote":{"type":"object","required":["feeMode","creditsUsd","credits","feeUsd","totalUsd"],"properties":{"feeMode":{"type":"string","enum":["pass_through","absorb"]},"creditsUsd":{"type":"string"},"credits":{"type":"string"},"feeUsd":{"type":"string"},"totalUsd":{"type":"string"},"bonus":{"type":["object","null"],"description":"Volume bonus this amount earns (POST /topups/quote only; tenant pool top-ups). Null when no tier is reached; end-user purchases never earn one.","required":["bonusUsd","bonusCredits","bonusBps"],"properties":{"bonusUsd":{"type":"string","description":"USD value of the bonus credits, 6dp decimal string."},"bonusCredits":{"type":"string","description":"bonusUsd in the tenant's display denomination."},"bonusBps":{"type":"integer","description":"Applied bonus rate in basis points."}}},"nextBonusTier":{"type":["object","null"],"description":"Cheapest volume-bonus tier this amount has NOT reached — the add-more upsell hint. Null at or above the top tier. POST /topups/quote only.","required":["minUsd","bonusBps"],"properties":{"minUsd":{"type":"string"},"bonusBps":{"type":"integer"}}}}},"TopupSession":{"type":"object","required":["success","sessionId","url","externalUserId","quote"],"properties":{"success":{"const":true},"sessionId":{"type":"string","pattern":"^cs_"},"url":{"type":"string","format":"uri"},"externalUserId":{"type":["string","null"]},"quote":{"$ref":"#/components/schemas/TopupQuote"}}},"TopupSessionResponse":{"type":"object","required":["success","sessionId","url","externalUserId","quote"],"properties":{"success":{"type":"boolean","const":true},"sessionId":{"type":"string","pattern":"^cs_"},"url":{"type":"string","format":"uri"},"externalUserId":{"type":["string","null"]},"quote":{"$ref":"#/components/schemas/TopupQuote"},"bonus":{"type":"object","description":"Present only when this checkout session will mint a volume bonus on completion (tenant pool top-up reaching a tier).","required":["bonusUsd","bonusCredits","bonusBps"],"properties":{"bonusUsd":{"type":"string"},"bonusCredits":{"type":"string"},"bonusBps":{"type":"integer"}}}},"additionalProperties":false},"TopupConstraints":{"type":"object","required":["currency","minUsd","maxUsd","incrementUsd","maxAmountDecimalPlaces","amountEncoding","creditsPerDollar","purchasingEnabled","disabledReason"],"properties":{"currency":{"const":"USD"},"minUsd":{"type":"string","example":"5.00"},"maxUsd":{"type":["string","null"],"const":null,"description":"No fixed platform maximum; commercial and processor controls remain risk-based."},"incrementUsd":{"const":"0.01"},"maxAmountDecimalPlaces":{"const":6},"amountEncoding":{"const":"decimal_string"},"creditsPerDollar":{"type":"string"},"purchasingEnabled":{"type":"boolean","description":"False when this tenant cannot currently create checkout sessions or buy credits."},"disabledReason":{"type":["string","null"],"enum":["funding_unavailable",null]},"bonusTiers":{"type":"array","description":"Volume-bonus cliff tiers over creditsUsd — the highest reached tier applies to the whole purchase. Management surface only; omitted from the end-user /me config because end-user top-ups never earn a bonus.","items":{"type":"object","required":["minUsd","bonusBps"],"properties":{"minUsd":{"type":"string"},"bonusBps":{"type":"integer"}}}}}},"TopupConstraintsEnvelope":{"type":"object","required":["success","constraints"],"properties":{"success":{"const":true},"constraints":{"$ref":"#/components/schemas/TopupConstraints"}}},"TopupStatus":{"type":"object","required":["success","sessionId","state","paymentStatus"],"properties":{"success":{"const":true},"sessionId":{"type":"string"},"state":{"type":"string","enum":["pending","completed","expired"]},"paymentStatus":{"type":"string"},"fulfillment":{"type":"string","enum":["awaiting_payment","processing","ready","expired","failed"],"description":"Ledger state. `completed` means Stripe was paid; credits are spendable once this is `ready`."}}},"TopupError":{"type":"object","required":["success","error","code","message"],"properties":{"success":{"const":false},"error":{"type":"string"},"code":{"type":"string","enum":["below_minimum","not_whole_cents","invalid_amount","invalid_amount_choice","invalid_request","invalid_url","invalid_external_user_id","invalid_metadata","identity_not_allowed","unknown_field","invalid_session_id","tenant_unavailable","missing_stripe_customer"]},"message":{"type":"string"}}},"TopupErrorResponse":{"type":"object","required":["success","error","code","message"],"properties":{"success":{"type":"boolean","const":false},"error":{"type":"string"},"code":{"type":"string","enum":["below_minimum","not_whole_cents","invalid_amount","invalid_amount_choice","invalid_request","invalid_url","invalid_external_user_id","invalid_metadata","identity_not_allowed","unknown_field","invalid_session_id","tenant_unavailable","missing_stripe_customer"]},"message":{"type":"string"}},"additionalProperties":false},"Tenant":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["active","suspended"]},"secretKeyPrefix":{"type":"string","example":"lcr_live_ab12"},"publishableKeyPrefix":{"type":"string","example":"lcrpk_live_cd34"},"defaultMarkupBps":{"type":"integer"},"feeMode":{"type":"string","enum":["pass_through","absorb"]},"provisioningSource":{"type":"string","enum":["operator","self_serve","system"]},"creditsPerDollar":{"type":"integer"}}},"TenantCreated":{"type":"object","required":["success","tenant","keys"],"properties":{"success":{"const":true},"tenant":{"$ref":"#/components/schemas/Tenant"},"keys":{"type":"object","required":["secretKey","publishableKey","webhookSecret"],"properties":{"secretKey":{"type":"string","description":"Shown exactly once"},"publishableKey":{"type":"string","description":"Shown exactly once"},"webhookSecret":{"type":["string","null"],"pattern":"^whsec_","description":"Always null during initial account creation. Configure and verify a destination after onboarding, then explicitly reveal the secret once."}},"additionalProperties":false}},"additionalProperties":false},"TransferResult":{"type":"object","required":["success","externalUserId","usd","credits","poolBalanceUsd","endUserBalanceUsd"],"properties":{"success":{"const":true},"externalUserId":{"$ref":"#/components/schemas/ExternalUserId"},"usd":{"$ref":"#/components/schemas/DecimalString"},"credits":{"$ref":"#/components/schemas/DecimalString"},"poolBalanceUsd":{"$ref":"#/components/schemas/DecimalString"},"endUserBalanceUsd":{"$ref":"#/components/schemas/DecimalString"}},"additionalProperties":false},"McpOAuthError":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"OAuth protocol error code."},"error_description":{"type":"string"}},"additionalProperties":false},"McpProtectedResourceMetadata":{"type":"object","required":["resource","authorization_servers","bearer_methods_supported","scopes_supported","resource_name","resource_documentation"],"properties":{"resource":{"type":"string","format":"uri"},"authorization_servers":{"type":"array","minItems":1,"items":{"type":"string","format":"uri"}},"bearer_methods_supported":{"type":"array","items":{"type":"string"},"example":["header"]},"scopes_supported":{"type":"array","items":{"type":"string","enum":["mcp:read","mcp:execute","offline_access"]}},"resource_name":{"type":"string","const":"Locus Pro MCP"},"resource_documentation":{"type":"string","format":"uri"}},"additionalProperties":false},"McpAuthorizationServerMetadata":{"type":"object","required":["issuer","authorization_endpoint","device_authorization_endpoint","token_endpoint","registration_endpoint","revocation_endpoint","response_types_supported","response_modes_supported","grant_types_supported","token_endpoint_auth_methods_supported","revocation_endpoint_auth_methods_supported","code_challenge_methods_supported","scopes_supported","authorization_response_iss_parameter_supported","resource_parameter_supported","client_id_metadata_document_supported"],"properties":{"issuer":{"type":"string","format":"uri"},"authorization_endpoint":{"type":"string","format":"uri"},"device_authorization_endpoint":{"type":"string","format":"uri"},"token_endpoint":{"type":"string","format":"uri"},"registration_endpoint":{"type":"string","format":"uri"},"revocation_endpoint":{"type":"string","format":"uri"},"response_types_supported":{"type":"array","items":{"type":"string"},"example":["code"]},"response_modes_supported":{"type":"array","items":{"type":"string"},"example":["query"]},"grant_types_supported":{"type":"array","items":{"type":"string","enum":["authorization_code","refresh_token","urn:ietf:params:oauth:grant-type:device_code"]}},"token_endpoint_auth_methods_supported":{"type":"array","items":{"type":"string"},"example":["none"]},"revocation_endpoint_auth_methods_supported":{"type":"array","items":{"type":"string"},"example":["none"]},"code_challenge_methods_supported":{"type":"array","items":{"type":"string"},"example":["S256"]},"scopes_supported":{"type":"array","items":{"type":"string","enum":["mcp:read","mcp:execute","offline_access"]}},"authorization_response_iss_parameter_supported":{"type":"boolean","const":true},"resource_parameter_supported":{"type":"boolean","const":true},"client_id_metadata_document_supported":{"type":"boolean","const":true}},"additionalProperties":false},"McpOAuthDeviceUserCode":{"type":"string","pattern":"^[A-HJ-NP-Z2-9]{3}-[A-HJ-NP-Z2-9]{3}$","description":"Human-readable code that omits ambiguous characters. Display it exactly as returned."},"McpOAuthDeviceUserCodeInput":{"type":"string","pattern":"^[^A-Za-z0-9]*[A-HJ-NP-Za-hj-np-z2-9](?:[^A-Za-z0-9]*[A-HJ-NP-Za-hj-np-z2-9]){5}[^A-Za-z0-9]*$","description":"Case-insensitive device-code input. Locus ignores non-alphanumeric punctuation, rejects ambiguous characters, and normalizes the six significant characters to XXX-XXX."},"McpOAuthDeviceAuthorizationRequest":{"type":"object","additionalProperties":true,"required":["client_id","resource"],"properties":{"client_id":{"type":"string","minLength":1,"maxLength":2048},"resource":{"type":"string","format":"uri","description":"Exact Locus Pro MCP resource URL."},"scope":{"type":"string","maxLength":512,"example":"mcp:read mcp:execute offline_access"}}},"McpOAuthDeviceAuthorizationResponse":{"type":"object","additionalProperties":false,"required":["device_code","user_code","verification_uri","verification_uri_complete","expires_in","interval"],"properties":{"device_code":{"type":"string","pattern":"^lmo_dc_[A-Za-z0-9_-]{43}$","description":"Secret device grant credential. Keep it only in the client that initiated the device flow and do not log it."},"user_code":{"$ref":"#/components/schemas/McpOAuthDeviceUserCode"},"verification_uri":{"type":"string","format":"uri"},"verification_uri_complete":{"type":"string","format":"uri"},"expires_in":{"type":"integer","const":900},"interval":{"type":"integer","const":5,"description":"Initial minimum token-poll interval in seconds. A slow_down response increases it by five seconds, up to 60 seconds."}}},"McpConnectionCapacity":{"type":"object","additionalProperties":false,"required":["plan","limit","active","reserved","remaining"],"properties":{"plan":{"type":"string","enum":["free","plus","unlimited"]},"limit":{"type":["integer","null"],"minimum":1,"description":"Null for an unlimited plan or enterprise workspace."},"active":{"type":"integer","minimum":0},"reserved":{"type":"integer","minimum":0,"description":"Approved browser and device grants that have not yet been exchanged and have not expired."},"remaining":{"type":["integer","null"],"minimum":0}}},"McpOAuthDevicePublicContextResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["userCode","clientName","clientId","scopes","resource","expiresAt"],"properties":{"userCode":{"$ref":"#/components/schemas/McpOAuthDeviceUserCode"},"clientName":{"type":"string"},"clientId":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["mcp:read","mcp:execute","offline_access"]}},"resource":{"type":"string","format":"uri"},"expiresAt":{"type":"string","format":"date-time"}}}}},"McpOAuthDeviceTenantListResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["tenants","selectedTenantId"],"properties":{"tenants":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["id","name","role"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"role":{"$ref":"#/components/schemas/WorkspaceRole"}}}},"selectedTenantId":{"type":["string","null"],"format":"uuid"}}}}},"McpOAuthDeviceContextResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["userCode","clientName","clientId","tenantName","scopes","scopeReduced","connectionCapacity","resource","expiresAt"],"properties":{"userCode":{"$ref":"#/components/schemas/McpOAuthDeviceUserCode"},"clientName":{"type":"string"},"clientId":{"type":"string"},"tenantName":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["mcp:read","mcp:execute","offline_access"]}},"scopeReduced":{"type":"boolean"},"connectionCapacity":{"$ref":"#/components/schemas/McpConnectionCapacity"},"resource":{"type":"string","format":"uri"},"expiresAt":{"type":"string","format":"date-time"}}}}},"McpOAuthDeviceDecisionResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["status"],"properties":{"status":{"type":"string","enum":["approved","denied"]}}}}},"McpOAuthTokenRequest":{"oneOf":[{"type":"object","title":"Authorization code exchange","required":["grant_type","client_id","resource","code","redirect_uri","code_verifier"],"properties":{"grant_type":{"const":"authorization_code"},"client_id":{"type":"string"},"resource":{"type":"string","format":"uri"},"code":{"type":"string"},"redirect_uri":{"type":"string","format":"uri"},"code_verifier":{"type":"string"}},"additionalProperties":true},{"type":"object","title":"Device-code exchange","required":["grant_type","client_id","resource","device_code"],"properties":{"grant_type":{"const":"urn:ietf:params:oauth:grant-type:device_code"},"client_id":{"type":"string"},"resource":{"type":"string","format":"uri"},"device_code":{"type":"string","pattern":"^lmo_dc_[A-Za-z0-9_-]{43}$"}},"additionalProperties":true},{"type":"object","title":"Refresh token exchange","required":["grant_type","client_id","resource","refresh_token"],"properties":{"grant_type":{"const":"refresh_token"},"client_id":{"type":"string"},"resource":{"type":"string","format":"uri"},"refresh_token":{"type":"string"},"scope":{"type":"string"}},"additionalProperties":true}]},"McpOAuthTokenResponse":{"type":"object","required":["access_token","token_type","expires_in","scope","resource"],"properties":{"access_token":{"type":"string"},"token_type":{"type":"string","const":"Bearer"},"expires_in":{"type":"integer","minimum":1},"refresh_token":{"type":"string","description":"Present when offline_access was granted; rotated on every refresh."},"scope":{"type":"string"},"resource":{"type":"string","format":"uri"}},"additionalProperties":false},"McpOAuthClientMetadata":{"type":"object","allOf":[{"anyOf":[{"not":{"required":["grant_types"]}},{"required":["grant_types"],"properties":{"grant_types":{"contains":{"const":"authorization_code"}}}},{"required":["grant_types"],"properties":{"grant_types":{"contains":{"const":"urn:ietf:params:oauth:grant-type:device_code"}}}}]},{"if":{"anyOf":[{"not":{"required":["grant_types"]}},{"required":["grant_types"],"properties":{"grant_types":{"contains":{"const":"authorization_code"}}}}]},"then":{"required":["redirect_uris"],"properties":{"redirect_uris":{"minItems":1},"response_types":{"minItems":1,"maxItems":1}}},"else":{"properties":{"response_types":{"maxItems":0}}}}],"properties":{"client_name":{"type":"string","maxLength":120},"application_type":{"type":"string","enum":["native","web"]},"redirect_uris":{"type":"array","minItems":0,"maxItems":10,"uniqueItems":true,"items":{"type":"string","format":"uri"},"description":"Required and non-empty when grant_types contains authorization_code; may be empty for a device-only client."},"grant_types":{"type":"array","minItems":1,"maxItems":3,"uniqueItems":true,"items":{"type":"string","enum":["authorization_code","refresh_token","urn:ietf:params:oauth:grant-type:device_code"]},"default":["authorization_code"],"description":"Must contain authorization_code or the device-code grant. refresh_token may accompany either."},"response_types":{"type":"array","minItems":0,"maxItems":1,"uniqueItems":true,"items":{"type":"string","const":"code"},"description":"Exactly [\"code\"] for authorization_code clients and [] for device-only clients."},"token_endpoint_auth_method":{"type":"string","const":"none"},"client_uri":{"type":"string","format":"uri"},"logo_uri":{"type":"string","format":"uri"}},"additionalProperties":true},"McpOAuthClientMetadataUpdate":{"allOf":[{"$ref":"#/components/schemas/McpOAuthClientMetadata"},{"type":"object","required":["client_id"],"properties":{"client_id":{"type":"string","description":"Must exactly match the clientId path parameter."}}}]},"McpOAuthClientRegistration":{"allOf":[{"$ref":"#/components/schemas/McpOAuthClientMetadata"},{"type":"object","required":["client_id","client_id_issued_at","client_name","application_type","redirect_uris","grant_types","response_types","token_endpoint_auth_method","registration_client_uri"],"properties":{"client_id":{"type":"string"},"client_id_issued_at":{"type":"integer"},"registration_client_uri":{"type":"string","format":"uri"},"registration_access_token":{"type":"string","description":"Returned only when the client is created; show and store it once."}}}]},"PersonalCatalogTenant":{"type":"object","required":["creditsPerDollar"],"properties":{"creditsPerDollar":{"type":"integer","minimum":1}},"additionalProperties":false},"PersonalCatalogEndpoint":{"type":"object","required":["slug","method","dynamic","enabled","mcpPinned","chargedUsdc","effectiveUsd","effectiveCredits"],"properties":{"slug":{"type":"string"},"method":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"dynamic":{"type":"boolean"},"estimatedCost":{"type":"string","description":"Display-only quoted range for variable-price actions."},"billingModel":{"type":"string","enum":["usage","prepaid_runtime"],"description":"Variable charge collection model; omitted for ordinary fixed-price actions."},"enabled":{"type":"boolean"},"mcpPinned":{"type":"boolean"},"availability":{"type":"string","enum":["available","temporarily_unavailable","unknown"],"description":"Current platform readiness. This is separate from tenant enablement."},"unavailableReason":{"type":["string","null"],"enum":["delivery_breaker","platform_pause",null]},"systemManaged":{"const":true},"chargedUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"effectiveUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"effectiveCredits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]}},"additionalProperties":false},"PersonalCatalogProvider":{"type":"object","required":["provider","logoUrl","serviceUrl","endpoints"],"properties":{"provider":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"secondaryCategories":{"type":"array","items":{"type":"string"},"description":"Additional marketplace categories beyond the primary (Parse), so catalogs can file a provider under every category its marketplace lists it in."},"verified":{"type":"boolean","description":"Whether the provider listing has been explicitly verified by its source catalog."},"logoUrl":{"type":"string","format":"uri"},"serviceUrl":{"type":"string","format":"uri"},"websiteUrl":{"type":"string","format":"uri"},"docsUrl":{"type":"string","format":"uri"},"marketplaceRank":{"type":"integer"},"marketplaceFeatured":{"type":"boolean"},"externalRail":{"type":"string","enum":["mpp","x402"]},"availability":{"type":"string","enum":["available","temporarily_unavailable","unknown"],"description":"Current platform readiness. This is separate from tenant enablement."},"unavailableReason":{"type":["string","null"],"enum":["delivery_breaker","platform_pause",null]},"endpoints":{"type":"array","items":{"$ref":"#/components/schemas/PersonalCatalogEndpoint"}}},"additionalProperties":false},"PersonalDashboardCatalogResponse":{"type":"object","description":"Personal-account catalog projection. Upstream cost, margin, markup policy, and pricing provenance are removed at the API boundary.","required":["success","version","view","tenant","providers","nextCursor"],"properties":{"success":{"const":true},"version":{"type":"string","const":"2026-09-06"},"view":{"type":"string","const":"dashboard"},"tenant":{"$ref":"#/components/schemas/PersonalCatalogTenant"},"providers":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/PersonalCatalogProvider"}},"nextCursor":{"type":["string","null"]},"filter":{"type":"object","required":["enabled"],"properties":{"enabled":{"const":true}},"additionalProperties":false,"description":"Present when the page was narrowed by enabled=true."},"pageCursors":{"type":"array","maxItems":100,"items":{"type":"string","maxLength":512}}},"additionalProperties":false},"PersonalCatalogProviderDetailResponse":{"type":"object","required":["success","version","view","tenant","provider"],"properties":{"success":{"const":true},"version":{"type":"string","const":"2026-09-06"},"view":{"type":"string","const":"detail"},"tenant":{"$ref":"#/components/schemas/PersonalCatalogTenant"},"provider":{"$ref":"#/components/schemas/PersonalCatalogProvider"}},"additionalProperties":false},"PersonalCatalogMutationRequest":{"type":"object","title":"Personal catalog mutation","required":["enabled"],"properties":{"enabled":{"type":"boolean"}},"additionalProperties":false},"PersonalCatalogMutationResponse":{"type":"object","required":["success","config"],"properties":{"success":{"const":true},"config":{"type":"object","required":["endpointSlug","enabled"],"properties":{"endpointSlug":{"type":"string"},"enabled":{"type":"boolean","description":"Effective enablement after this write."}},"additionalProperties":false}},"additionalProperties":false},"DashboardCatalogSummaryProvider":{"type":"object","required":["provider","logoUrl","serviceUrl","endpointCount","enabledEndpointCount","mutableEndpointCount","enabledMutableEndpointCount"],"properties":{"provider":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"secondaryCategories":{"type":"array","items":{"type":"string"},"description":"Additional marketplace categories beyond the primary (Parse), so catalogs can file a provider under every category its marketplace lists it in."},"verified":{"type":"boolean","description":"Whether the provider listing has been explicitly verified by its source catalog."},"logoUrl":{"type":"string","format":"uri"},"serviceUrl":{"type":"string","format":"uri"},"websiteUrl":{"type":"string","format":"uri"},"docsUrl":{"type":"string","format":"uri"},"catalogIdentity":{"type":"string"},"attribution":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"websiteUrl":{"type":"string","format":"uri"},"logoUrl":{"type":"string","format":"uri"}},"additionalProperties":false},"marketplaceRank":{"type":"integer"},"marketplaceFeatured":{"type":"boolean"},"catalogPriority":{"type":"integer","description":"Cross-surface browse priority for deliberately featured providers."},"externalRail":{"type":"string","enum":["mpp","x402"]},"availability":{"type":"string","enum":["available","temporarily_unavailable","unknown"],"description":"Current platform readiness. This is separate from tenant enablement."},"unavailableReason":{"type":["string","null"],"enum":["delivery_breaker","platform_pause",null]},"endpointCount":{"type":"integer","minimum":0},"enabledEndpointCount":{"type":"integer","minimum":0},"mutableEndpointCount":{"type":"integer","minimum":0},"enabledMutableEndpointCount":{"type":"integer","minimum":0},"callableEndpointCount":{"type":"integer","minimum":0,"description":"Enabled endpoints that are currently callable. Present for external rails."}},"additionalProperties":false},"DashboardCatalogSummaryResponse":{"type":"object","required":["success","version","view","tenant","providers"],"properties":{"success":{"const":true},"version":{"type":"string","const":"2026-09-06"},"view":{"type":"string","const":"summary"},"tenant":{"oneOf":[{"$ref":"#/components/schemas/PersonalCatalogTenant"},{"type":"object","required":["defaultMarkupBps","defaultFlatMarkupUsd","creditsPerDollar"],"properties":{"defaultMarkupBps":{"type":"integer"},"defaultFlatMarkupUsd":{"$ref":"#/components/schemas/DecimalString"},"creditsPerDollar":{"type":"integer","minimum":1}},"additionalProperties":false}]},"providers":{"type":"array","items":{"$ref":"#/components/schemas/DashboardCatalogSummaryProvider"}}},"additionalProperties":false},"ManagementCatalogSearchMatch":{"type":"object","additionalProperties":false,"required":["slug","provider","providerName","endpoint","title","description","enabled","availability","unavailableReason"],"properties":{"slug":{"type":"string","pattern":"^[^/]+/[^/]+$"},"provider":{"type":"string"},"providerName":{"type":"string"},"endpoint":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"enabled":{"type":"boolean","description":"The account's desired enablement. This is separate from current platform availability."},"availability":{"type":"string","enum":["available","temporarily_unavailable","unknown"]},"unavailableReason":{"type":["string","null"],"enum":["delivery_breaker","platform_pause",null]}}},"ManagementCatalogSearchResponse":{"type":"object","additionalProperties":false,"required":["success","query","count","results"],"properties":{"success":{"const":true},"query":{"type":"string"},"count":{"type":"integer","minimum":0,"maximum":50},"results":{"type":"array","maxItems":50,"items":{"$ref":"#/components/schemas/ManagementCatalogSearchMatch"}},"note":{"type":"string","description":"Present when no catalog endpoint matched."}}},"CustomAuthInput":{"type":"object","additionalProperties":false,"required":["type"],"properties":{"type":{"type":"string","enum":["bearer","header","query","none"]},"name":{"type":"string","minLength":1,"maxLength":100,"description":"Required for header and query authentication; must be a valid HTTP field name."},"prefix":{"type":"string","maxLength":80,"description":"Optional value prefix for header or query authentication. Bearer authentication always uses 'Bearer '."},"credential":{"type":"string","minLength":1,"maxLength":4096,"writeOnly":true,"description":"Required when creating a bearer, header, or query provider. Omit during an update to retain the encrypted credential. Never returned."}},"description":"For type=none, omit credential. For type=header or type=query, supply name."},"CustomAuthView":{"type":"object","additionalProperties":false,"required":["type","name","prefix","configured","hint","version","updatedAt"],"properties":{"type":{"type":["string","null"],"enum":["bearer","header","query","none",null],"description":"Null when upstream configuration is redacted for this caller."},"name":{"type":["string","null"]},"prefix":{"type":["string","null"]},"configured":{"type":"boolean"},"hint":{"type":["string","null"],"description":"Non-secret credential hint for an authorized owner; never the credential itself."},"version":{"type":"integer","minimum":0},"updatedAt":{"type":["string","null"],"format":"date-time"}}},"CustomCircuitBreakerPolicy":{"type":"object","additionalProperties":false,"required":["failureThreshold","windowSeconds","cooldownSeconds"],"properties":{"failureThreshold":{"type":"integer","minimum":2,"maximum":100},"windowSeconds":{"type":"integer","minimum":1,"maximum":600},"cooldownSeconds":{"type":"integer","minimum":1,"maximum":3600}}},"CustomTrafficPolicy":{"type":"object","additionalProperties":false,"required":["requestsPerMinute","maxConcurrency","timeoutSeconds","circuitBreaker"],"properties":{"requestsPerMinute":{"type":"integer","minimum":1,"maximum":60000,"description":"Must not exceed the platform-wide 60,000 request-per-minute ceiling."},"maxConcurrency":{"type":"integer","minimum":1,"maximum":1000},"timeoutSeconds":{"type":"integer","minimum":1,"maximum":120},"circuitBreaker":{"$ref":"#/components/schemas/CustomCircuitBreakerPolicy"}}},"CustomTrafficPolicyUpdate":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"requestsPerMinute":{"type":"integer","minimum":1,"maximum":60000},"maxConcurrency":{"type":"integer","minimum":1,"maximum":1000},"timeoutSeconds":{"type":"integer","minimum":1,"maximum":120},"circuitBreaker":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"failureThreshold":{"type":"integer","minimum":2,"maximum":100},"windowSeconds":{"type":"integer","minimum":1,"maximum":600},"cooldownSeconds":{"type":"integer","minimum":1,"maximum":3600}}}}},"CustomEndpointCreateRequest":{"type":"object","additionalProperties":false,"required":["slug","name","description","method","path","inputSchema","inputExample","providerCostUsdc","markupBps","flatMarkupUsdc"],"properties":{"slug":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$","description":"Stable 3–64 character action name."},"name":{"type":"string","minLength":1,"maxLength":80},"description":{"type":"string","minLength":1,"maxLength":500},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"]},"path":{"type":"string","minLength":1,"maxLength":1024,"description":"Upstream path. Placeholders must reference required scalar properties from inputSchema."},"inputSchema":{"type":"object","additionalProperties":true,"description":"Compilable JSON Schema, at most 64 KiB and 32 levels deep, whose root type is object. Top-level transport-control names are reserved."},"inputExample":{"type":"object","additionalProperties":true,"description":"Executable example that must satisfy inputSchema."},"outputSchema":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"null"}],"description":"Optional JSON Schema, at most 64 KiB and 32 levels deep."},"outputExample":{"description":"Optional example that must satisfy outputSchema when both are provided."},"providerCostUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"number","minimum":0}],"description":"Upstream provider cost in USD, rounded up to six decimal places."},"markupBps":{"type":"integer","minimum":0,"maximum":10000,"description":"Percentage markup, also limited by the workspace's effective cap."},"flatMarkupUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"number","minimum":0}],"description":"Flat USD markup, also limited by the workspace's effective cap."},"enabled":{"type":"boolean","default":false,"description":"Enabled actions must have a positive end-user price."}}},"CustomEndpointUpdateRequest":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"name":{"type":"string","minLength":1,"maxLength":80},"description":{"type":"string","minLength":1,"maxLength":500},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"]},"path":{"type":"string","minLength":1,"maxLength":1024},"inputSchema":{"type":"object","additionalProperties":true},"inputExample":{"type":"object","additionalProperties":true},"outputSchema":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"outputExample":{},"providerCostUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"number","minimum":0}]},"markupBps":{"type":"integer","minimum":0,"maximum":10000},"flatMarkupUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"number","minimum":0}]},"enabled":{"type":"boolean"}},"description":"Any non-empty subset of the create fields except slug. Unspecified fields remain unchanged; all affected contracts and prices are revalidated."},"CustomEndpoint":{"type":"object","additionalProperties":false,"required":["id","slug","publicSlug","name","description","method","path","inputSchema","inputExample","outputSchema","outputExample","providerCostUsdc","markupBps","flatMarkupUsdc","endUserPriceUsdc","enabled","pricingRevision","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"publicSlug":{"type":"string","pattern":"^custom-[^/]+/[^/]+$","description":"Catalog and execution identity."},"name":{"type":"string"},"description":{"type":"string"},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"]},"path":{"type":"string"},"inputSchema":{"type":"object","additionalProperties":true},"inputExample":{"type":"object","additionalProperties":true},"outputSchema":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"outputExample":{},"providerCostUsdc":{"$ref":"#/components/schemas/DecimalString"},"markupBps":{"type":"integer","minimum":0},"flatMarkupUsdc":{"$ref":"#/components/schemas/DecimalString"},"endUserPriceUsdc":{"$ref":"#/components/schemas/DecimalString"},"enabled":{"type":"boolean"},"pricingRevision":{"type":"integer","minimum":0},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CustomProviderCreateRequest":{"type":"object","additionalProperties":false,"required":["slug","name","baseUrl","auth"],"properties":{"slug":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$","description":"Stable provider name. The public catalog name is custom-{slug}."},"name":{"type":"string","minLength":1,"maxLength":80},"description":{"type":"string","maxLength":500},"baseUrl":{"type":"string","format":"uri","maxLength":2048,"description":"HTTPS upstream origin validated against SSRF and private-network controls."},"auth":{"$ref":"#/components/schemas/CustomAuthInput"},"traffic":{"$ref":"#/components/schemas/CustomTrafficPolicy"},"endpoint":{"$ref":"#/components/schemas/CustomEndpointCreateRequest"},"endpoints":{"type":"array","minItems":1,"maxItems":50,"items":{"$ref":"#/components/schemas/CustomEndpointCreateRequest"},"description":"Use endpoint or endpoints, never both. Slugs must be unique within the request."}}},"CustomProviderUpdateRequest":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"name":{"type":"string","minLength":1,"maxLength":80},"description":{"type":["string","null"],"maxLength":500},"baseUrl":{"type":"string","format":"uri","maxLength":2048},"auth":{"$ref":"#/components/schemas/CustomAuthInput"},"traffic":{"$ref":"#/components/schemas/CustomTrafficPolicyUpdate"}}},"CustomProvider":{"type":"object","additionalProperties":false,"required":["id","slug","publicProvider","name","description","baseUrl","auth","traffic","endpoints","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"publicProvider":{"type":"string","pattern":"^custom-","description":"Provider name used in catalog discovery and /wrapped/credits/{provider}/{endpoint}."},"name":{"type":"string"},"description":{"type":["string","null"]},"baseUrl":{"type":["string","null"],"format":"uri","description":"Null when upstream configuration is redacted for this caller."},"auth":{"$ref":"#/components/schemas/CustomAuthView"},"traffic":{"$ref":"#/components/schemas/CustomTrafficPolicy"},"endpoints":{"type":"array","items":{"$ref":"#/components/schemas/CustomEndpoint"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CustomProviderListResponse":{"type":"object","additionalProperties":false,"required":["success","markupCapBps","providers"],"properties":{"success":{"const":true},"markupCapBps":{"type":"integer","minimum":0,"maximum":10000},"providers":{"type":"array","items":{"$ref":"#/components/schemas/CustomProvider"}}}},"CustomProviderResponse":{"type":"object","additionalProperties":false,"required":["success","provider"],"properties":{"success":{"const":true},"provider":{"$ref":"#/components/schemas/CustomProvider"}}},"CustomEndpointResponse":{"type":"object","additionalProperties":false,"required":["success","endpoint"],"properties":{"success":{"const":true},"endpoint":{"$ref":"#/components/schemas/CustomEndpoint"}}},"TravelFlightSearchRequest":{"type":"object","additionalProperties":false,"required":["origin","destination","departureDate"],"properties":{"origin":{"type":"string","minLength":2,"maxLength":120,"description":"IATA code or place name. Three-letter codes are normalized to uppercase."},"destination":{"type":"string","minLength":2,"maxLength":120,"description":"Must differ from origin."},"departureDate":{"type":"string","format":"date","description":"Real calendar date in YYYY-MM-DD form."},"returnDate":{"type":"string","format":"date","description":"Optional return date on or after departureDate."},"adults":{"type":"integer","minimum":1,"maximum":9,"default":1},"children":{"type":"integer","minimum":0,"maximum":8,"default":0},"infants":{"type":"integer","minimum":0,"maximum":4,"default":0,"description":"Cannot exceed adults. Total travelers cannot exceed nine."},"cabinClass":{"type":"string","enum":["economy","premium_economy","business","first"],"default":"economy"},"currency":{"type":"string","pattern":"^[A-Za-z]{3}$","default":"USD"},"optimize":{"type":"array","maxItems":3,"uniqueItems":true,"items":{"type":"string","enum":["cost","quality","context"]},"description":"Cost favors fewer inexpensive sources, quality increases depth, and context favors compact agent-readable output."},"preferredAirlines":{"type":"array","maxItems":20,"uniqueItems":true,"items":{"type":"string","minLength":1,"maxLength":100}},"excludedAirlines":{"type":"array","maxItems":20,"uniqueItems":true,"items":{"type":"string","minLength":1,"maxLength":100}},"preferredAirports":{"type":"array","maxItems":20,"uniqueItems":true,"items":{"type":"string","minLength":1,"maxLength":100}},"excludedAirports":{"type":"array","maxItems":20,"uniqueItems":true,"items":{"type":"string","minLength":1,"maxLength":100}},"maxStops":{"type":"integer","minimum":0,"maximum":3},"minLayoverMinutes":{"type":"integer","minimum":0,"maximum":1440},"maxLayoverMinutes":{"type":"integer","minimum":0,"maximum":2880},"maxDurationMinutes":{"type":"integer","minimum":30,"maximum":10080},"maxPrice":{"type":"number","exclusiveMinimum":0,"maximum":10000000,"description":"Maximum itinerary price in currency."},"departAfter":{"type":"string","pattern":"^(?:[01]\\d|2[0-3]):[0-5]\\d$"},"departBefore":{"type":"string","pattern":"^(?:[01]\\d|2[0-3]):[0-5]\\d$"},"arriveAfter":{"type":"string","pattern":"^(?:[01]\\d|2[0-3]):[0-5]\\d$"},"arriveBefore":{"type":"string","pattern":"^(?:[01]\\d|2[0-3]):[0-5]\\d$"},"maxResults":{"type":"integer","minimum":1,"maximum":50},"maxProviders":{"type":"integer","minimum":1,"maximum":11},"providers":{"type":"array","maxItems":11,"uniqueItems":true,"items":{"type":"string","enum":["aircanada","duffel","stabletravel","almosafer","flightconnections","justfly","kayak_hk","skyscanner","skiplagged","trip","united"]},"description":"Optional explicit provider selection, still narrowed by credential, catalog, availability, and request compatibility."},"maxCredits":{"oneOf":[{"type":"string","pattern":"^(?:0*[1-9]\\d*)(?:\\.\\d{1,6})?$|^0*\\.0*[1-9]\\d{0,5}$"},{"type":"number","exclusiveMinimum":0,"maximum":1000000000000}],"description":"Aggregate no-dispatch ceiling for all selected child calls, in account credits."},"externalUserId":{"$ref":"#/components/schemas/ExternalUserId"},"attribution":{"type":"object","additionalProperties":true,"description":"Optional JSON attribution copied to child calls."}},"description":"Preferred and excluded values cannot overlap. minLayoverMinutes cannot exceed maxLayoverMinutes. Defaults are selected from optimize when optional depth controls are absent."},"TravelFlightSearchPreview":{"type":"object","additionalProperties":false,"required":["object","capability","request","providers","eligibleProviders","ineligibleProviders","estimatedCostCredits","estimateExact"],"properties":{"object":{"const":"locus.travel_flight_search.preview"},"capability":{"const":"travel.flight_search"},"request":{"$ref":"#/components/schemas/TravelFlightSearchRequest"},"providers":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["providerId","providerName","estimatedCostCredits","priceExact"],"properties":{"providerId":{"type":"string"},"providerName":{"type":"string"},"estimatedCostCredits":{"$ref":"#/components/schemas/DecimalString"},"priceExact":{"type":"boolean"},"estimatedCostUsd":{"type":"number","minimum":0,"description":"Shown only to secret-key and dashboard principals."}}}},"eligibleProviders":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["providerId","providerName"],"properties":{"providerId":{"type":"string"},"providerName":{"type":"string"}}}},"ineligibleProviders":{"type":"array","items":{"$ref":"#/components/schemas/TravelIneligibleProvider"}},"estimatedCostCredits":{"$ref":"#/components/schemas/DecimalString"},"estimateExact":{"type":"boolean"},"estimatedCostUsd":{"type":"number","minimum":0,"description":"Shown only to secret-key and dashboard principals."}}},"TravelIneligibleProvider":{"type":"object","additionalProperties":false,"required":["providerId","providerName","reason"],"properties":{"providerId":{"type":"string"},"providerName":{"type":"string"},"reason":{"type":"string","enum":["credential_scope","provider_disabled","provider_filtered","provider_unavailable","request_unsupported"]},"detail":{"type":"string"}}},"TravelPlace":{"type":"object","additionalProperties":false,"required":["code"],"properties":{"code":{"type":"string"},"name":{"type":"string"},"city":{"type":"string"}}},"TravelSegment":{"type":"object","additionalProperties":false,"required":["origin","destination","departure","arrival"],"properties":{"origin":{"$ref":"#/components/schemas/TravelPlace"},"destination":{"$ref":"#/components/schemas/TravelPlace"},"departure":{"type":"string","description":"Provider-normalized departure timestamp."},"arrival":{"type":"string","description":"Provider-normalized arrival timestamp."},"durationMinutes":{"type":"integer","minimum":0},"flightNumber":{"type":"string"},"marketingCarrier":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string"},"name":{"type":"string"}}},"operatingCarrier":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string"},"name":{"type":"string"}}},"aircraft":{"type":"string"}}},"TravelLeg":{"type":"object","additionalProperties":false,"required":["origin","destination","departure","arrival","stopCount","segments"],"properties":{"origin":{"$ref":"#/components/schemas/TravelPlace"},"destination":{"$ref":"#/components/schemas/TravelPlace"},"departure":{"type":"string"},"arrival":{"type":"string"},"durationMinutes":{"type":"integer","minimum":0},"stopCount":{"type":"integer","minimum":0},"segments":{"type":"array","items":{"$ref":"#/components/schemas/TravelSegment"}},"intermediateAirports":{"type":"array","items":{"$ref":"#/components/schemas/TravelPlace"}},"layoverDurationsMinutes":{"type":"array","items":{"type":"integer","minimum":0}}}},"TravelOffer":{"type":"object","additionalProperties":false,"required":["amount","currency","providerId","providerName"],"properties":{"amount":{"type":"number","minimum":0},"currency":{"type":"string"},"formatted":{"type":"string"},"bookingUrl":{"type":"string","format":"uri"},"linkType":{"type":"string","enum":["booking","search_handoff"]},"seller":{"type":"string"},"cabinClass":{"type":"string","enum":["economy","premium_economy","business","first"]},"refundable":{"type":"boolean"},"providerId":{"type":"string"},"providerName":{"type":"string"}}},"TravelItinerary":{"type":"object","additionalProperties":false,"required":["id","score","legs","offers","tags","confidence","sources","sourceCount","bookability"],"properties":{"id":{"type":"string"},"score":{"type":"number"},"providerItineraryId":{"type":"string","description":"Provider-native itinerary ID when one canonical source supplies it."},"legs":{"type":"array","items":{"$ref":"#/components/schemas/TravelLeg"}},"offers":{"type":"array","items":{"$ref":"#/components/schemas/TravelOffer"}},"tags":{"type":"array","items":{"type":"string"}},"selfTransfer":{"type":"boolean"},"baggage":{"type":"string"},"seatsRemaining":{"type":"integer","minimum":0},"confidence":{"type":"object","additionalProperties":false,"required":["score","sourceCount","scheduleAgreement"],"properties":{"score":{"type":"number"},"sourceCount":{"type":"integer","minimum":1},"scheduleAgreement":{"type":"string","enum":["single_source","corroborated"]},"priceSpreadPercent":{"type":"number","minimum":0}}},"sources":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["providerId","providerName","rank"],"properties":{"providerId":{"type":"string"},"providerName":{"type":"string"},"rank":{"type":"integer","minimum":0},"providerItineraryId":{"type":"string"}}}},"sourceCount":{"type":"integer","minimum":1},"bookability":{"type":"object","additionalProperties":false,"required":["status","offerCount","bookingLinkOfferCount","searchHandoffOfferCount","currency"],"properties":{"status":{"type":"string","enum":["booking_link_available","search_handoff_available","price_only"]},"offerCount":{"type":"integer","minimum":0},"bookingLinkOfferCount":{"type":"integer","minimum":0},"searchHandoffOfferCount":{"type":"integer","minimum":0},"cheapestBookableAmount":{"type":"number","minimum":0},"currency":{"type":"string"}}}}},"TravelProviderOutcome":{"type":"object","additionalProperties":false,"required":["providerId","providerName","status","latencyMs","itineraryCount","surfacedItineraryCount","uniqueSurfacedItineraryCount","tailLatencyContributionMs"],"properties":{"providerId":{"type":"string"},"providerName":{"type":"string"},"status":{"type":"string","enum":["succeeded","failed","pending"]},"latencyMs":{"type":"number","minimum":0},"itineraryCount":{"type":"integer","minimum":0},"surfacedItineraryCount":{"type":"integer","minimum":0},"uniqueSurfacedItineraryCount":{"type":"integer","minimum":0},"tailLatencyContributionMs":{"type":"number","minimum":0},"chargedCredits":{"$ref":"#/components/schemas/DecimalString"},"errorCode":{"type":"string"},"estimatedCostUsd":{"type":"number","minimum":0}}},"TravelFlightSearchResponse":{"type":"object","additionalProperties":false,"required":["object","capability","routerVersion","runId","search","appliedOptimizations","partial","warnings","providers","itineraries","itineraryCount","bookability","feedback","billing"],"properties":{"object":{"const":"locus.travel_flight_search"},"capability":{"const":"travel.flight_search"},"routerVersion":{"type":"string"},"runId":{"type":"string","format":"uuid"},"search":{"$ref":"#/components/schemas/TravelFlightSearchRequest"},"appliedOptimizations":{"type":"array","items":{"type":"string","enum":["cost","quality","context"]}},"partial":{"type":"boolean","description":"True when at least one selected provider did not produce a complete successful result."},"warnings":{"type":"array","items":{"type":"string"}},"providers":{"type":"array","items":{"$ref":"#/components/schemas/TravelProviderOutcome"}},"itineraries":{"type":"array","items":{"$ref":"#/components/schemas/TravelItinerary"}},"itineraryCount":{"type":"integer","minimum":0},"bookability":{"type":"object","additionalProperties":false,"required":["bookableItineraryCount","searchHandoffItineraryCount","bookingLinkOfferCount","searchHandoffOfferCount","offerCount"],"properties":{"bookableItineraryCount":{"type":"integer","minimum":0},"searchHandoffItineraryCount":{"type":"integer","minimum":0},"bookingLinkOfferCount":{"type":"integer","minimum":0},"searchHandoffOfferCount":{"type":"integer","minimum":0},"offerCount":{"type":"integer","minimum":0}}},"feedback":{"type":"object","additionalProperties":false,"required":["method","route","runId"],"properties":{"method":{"const":"POST"},"route":{"type":"string"},"runId":{"type":"string","format":"uuid"}}},"billing":{"type":"object","additionalProperties":false,"required":["chargedCredits","successfulProviders","attemptedProviders"],"properties":{"chargedCredits":{"$ref":"#/components/schemas/DecimalString"},"successfulProviders":{"type":"integer","minimum":0},"attemptedProviders":{"type":"integer","minimum":0}}}}},"TravelFlightSearchPending":{"type":"object","additionalProperties":false,"required":["object","capability","runId","status","message"],"properties":{"object":{"const":"locus.travel_flight_search.pending"},"capability":{"const":"travel.flight_search"},"runId":{"type":"string","format":"uuid"},"status":{"const":"processing"},"providers":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["providerId","providerName","status","latencyMs"],"properties":{"providerId":{"type":"string"},"providerName":{"type":"string"},"status":{"type":"string","enum":["succeeded","failed","pending"]},"latencyMs":{"type":"number","minimum":0}}}},"billing":{"type":"object","additionalProperties":false,"required":["chargedCredits"],"properties":{"chargedCredits":{"$ref":"#/components/schemas/DecimalString"}}},"message":{"type":"string"}}},"TravelFlightSearchFeedbackRequest":{"type":"object","additionalProperties":false,"required":["helpful"],"properties":{"helpful":{"type":"boolean"},"selectedItineraryId":{"type":"string","minLength":1,"maxLength":64},"reason":{"type":"string","enum":["price","schedule","missing_option","provider_quality","other"]},"note":{"type":"string","minLength":1,"maxLength":2000}}},"TravelFlightSearchFeedbackResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["runId","helpful","selectedItineraryId","reason","updatedAt"],"properties":{"runId":{"type":"string","format":"uuid"},"helpful":{"type":"boolean"},"selectedItineraryId":{"type":["string","null"]},"reason":{"type":["string","null"],"enum":["price","schedule","missing_option","provider_quality","other",null]},"updatedAt":{"type":"string","format":"date-time"}}}}},"ToolSearchMatch":{"type":"object","required":["slug","tool","provider","endpoint","title","enabled","description","category_ids","pack_ids","pricing","next_step"],"properties":{"slug":{"type":"string"},"tool":{"type":"string"},"provider":{"type":"string"},"endpoint":{"type":"string"},"title":{"type":"string"},"enabled":{"type":"boolean"},"description":{"type":"string"},"category":{"type":"string"},"category_ids":{"type":"array","items":{"type":"string"}},"pack_ids":{"type":"array","items":{"type":"string"}},"credits":{"$ref":"#/components/schemas/DecimalString"},"variableCost":{"const":true},"pricing":{"type":"object","required":["type","credits"],"properties":{"type":{"type":"string","enum":["fixed","variable"]},"credits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"min_credits":{"$ref":"#/components/schemas/DecimalString"},"max_credits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"cap_credits":{"$ref":"#/components/schemas/DecimalString"},"typical_credits":{}},"additionalProperties":false},"next_step":{"type":"object","required":["method","path","body"],"properties":{"method":{"const":"POST"},"path":{"type":"string","enum":["/api/credits/tools/describe","/api/credits/tools/access-requests"]},"body":{"type":"object","required":["slug"],"properties":{"slug":{"type":"string"},"operation_query":{"type":"string","maxLength":256}},"additionalProperties":false}},"additionalProperties":false}},"additionalProperties":false},"ToolDescribeResponse":{"type":"object","required":["success","tool"],"properties":{"success":{"const":true},"tool":{"type":"object","required":["slug","tool","provider","endpoint","title","enabled","description","contract_revision","contract_digest","pricing","method","path","inputSchema","exampleArguments","annotations","next_step"],"additionalProperties":true}},"additionalProperties":false},"ToolSearchResponse":{"type":"object","required":["success","query","taxonomy_revision","count","results"],"properties":{"success":{"const":true},"query":{"type":"string"},"taxonomy_revision":{"type":"string"},"appliedFilters":{"type":"object","additionalProperties":{"type":"string"}},"count":{"type":"integer","minimum":0,"maximum":50},"next_cursor":{"type":"string"},"facets":{"type":"array","maxItems":50,"items":{"type":"object","additionalProperties":true}},"results":{"type":"array","maxItems":50,"items":{"$ref":"#/components/schemas/ToolSearchMatch"}},"note":{"type":"string","description":"Present when no enabled tool matched."}},"additionalProperties":false},"CatalogResponse":{"type":"object","required":["success","version","view","tenant","providers"],"properties":{"success":{"const":true},"version":{"type":"string","const":"2026-09-06"},"view":{"type":"string","const":"full"},"tenant":{"type":"object","required":["defaultMarkupBps","defaultFlatMarkupUsd","creditsPerDollar"],"properties":{"defaultMarkupBps":{"type":"integer"},"defaultFlatMarkupUsd":{"$ref":"#/components/schemas/DecimalString"},"creditsPerDollar":{"type":"integer","minimum":1}},"additionalProperties":false},"providers":{"type":"array","items":{"$ref":"#/components/schemas/CatalogProvider"}}},"additionalProperties":false},"CompactCatalogResponse":{"type":"object","required":["success","version","view","tenant","providers","nextCursor"],"properties":{"success":{"const":true},"version":{"type":"string","const":"2026-09-06"},"view":{"type":"string","const":"compact"},"tenant":{"type":"object","required":["defaultMarkupBps","defaultFlatMarkupUsd","creditsPerDollar"],"properties":{"defaultMarkupBps":{"type":"integer"},"defaultFlatMarkupUsd":{"$ref":"#/components/schemas/DecimalString"},"creditsPerDollar":{"type":"integer","minimum":1}},"additionalProperties":false},"providers":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/CompactCatalogProvider"}},"nextCursor":{"type":["string","null"]}},"additionalProperties":false},"DashboardCatalogResponse":{"type":"object","description":"view=dashboard: the compact paging projected to the fields the Locus Pro dashboard renders. Same ETag/cache semantics as CompactCatalogResponse.","required":["success","version","view","tenant","providers","nextCursor"],"properties":{"success":{"const":true},"version":{"type":"string","const":"2026-09-06"},"view":{"type":"string","const":"dashboard"},"tenant":{"type":"object","required":["defaultMarkupBps","defaultFlatMarkupUsd","creditsPerDollar"],"properties":{"defaultMarkupBps":{"type":"integer"},"defaultFlatMarkupUsd":{"$ref":"#/components/schemas/DecimalString"},"creditsPerDollar":{"type":"integer","minimum":1}},"additionalProperties":false},"providers":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/DashboardCatalogProvider"}},"nextCursor":{"type":["string","null"]},"filter":{"type":"object","required":["enabled"],"properties":{"enabled":{"const":true}},"additionalProperties":false,"description":"Present when the page was narrowed by enabled=true."},"pageCursors":{"type":"array","maxItems":100,"items":{"type":"string","maxLength":512},"description":"First page only: the cursor of every following page, so the rest of the walk can be fetched concurrently. Omitted when the walk has more than 100 further pages. A page whose own nextCursor differs from the next published cursor signals a registry change; restart with nextCursor."}},"additionalProperties":false},"DashboardCatalogProvider":{"type":"object","required":["provider","logoUrl","serviceUrl","endpoints"],"properties":{"provider":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"secondaryCategories":{"type":"array","items":{"type":"string"},"description":"Additional marketplace categories beyond the primary (Parse), so catalogs can file a provider under every category its marketplace lists it in."},"verified":{"type":"boolean"},"logoUrl":{"type":"string","format":"uri"},"serviceUrl":{"type":"string","format":"uri"},"websiteUrl":{"type":"string","format":"uri"},"docsUrl":{"type":"string","format":"uri"},"catalogIdentity":{"type":"string"},"attribution":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"websiteUrl":{"type":"string","format":"uri"},"logoUrl":{"type":"string","format":"uri"}},"additionalProperties":false},"marketplaceRank":{"type":"integer"},"marketplaceFeatured":{"type":"boolean"},"catalogPriority":{"type":"integer"},"externalRail":{"type":"string","enum":["mpp","x402"]},"availability":{"type":"string","enum":["available","temporarily_unavailable","unknown"],"description":"Current platform readiness. This is separate from tenant enablement."},"unavailableReason":{"type":["string","null"],"enum":["delivery_breaker","platform_pause",null]},"endpoints":{"type":"array","items":{"$ref":"#/components/schemas/DashboardCatalogEndpoint"}}},"additionalProperties":false},"DashboardCatalogEndpoint":{"type":"object","required":["slug","method","dynamic","enabled","mcpPinned","overridden","markupBps","flatMarkupUsdc","baseUsdc","chargedUsdc","marginUsdc"],"properties":{"slug":{"type":"string"},"method":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"estimatedCost":{"type":"string","description":"Display-only estimate present for dynamic-price endpoints."},"billingModel":{"type":"string","enum":["usage","prepaid_runtime"],"description":"Variable charge collection model; omitted for ordinary fixed-price actions."},"dynamic":{"type":"boolean"},"enabled":{"type":"boolean"},"mcpPinned":{"type":"boolean"},"overridden":{"type":"boolean","description":"Markup or flat fee come from a row of this endpoint's own or its provider's, not the workspace default."},"availability":{"type":"string","enum":["available","temporarily_unavailable","unknown"],"description":"Current platform readiness. This is separate from tenant enablement."},"unavailableReason":{"type":["string","null"],"enum":["delivery_breaker","platform_pause",null]},"systemManaged":{"const":true},"route":{"type":"string"},"previewRoute":{"type":"string"},"markupBps":{"type":"integer"},"flatMarkupUsdc":{"$ref":"#/components/schemas/DecimalString"},"baseUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"chargedUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"marginUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]}},"additionalProperties":false},"CatalogProviderDetailResponse":{"type":"object","required":["success","version","view","tenant","provider"],"properties":{"success":{"const":true},"version":{"type":"string","const":"2026-09-06"},"view":{"type":"string","const":"detail"},"tenant":{"type":"object","required":["defaultMarkupBps","defaultFlatMarkupUsd","creditsPerDollar"],"properties":{"defaultMarkupBps":{"type":"integer"},"defaultFlatMarkupUsd":{"$ref":"#/components/schemas/DecimalString"},"creditsPerDollar":{"type":"integer","minimum":1}},"additionalProperties":false},"provider":{"$ref":"#/components/schemas/CatalogProvider"}},"additionalProperties":false},"CatalogProvider":{"type":"object","required":["provider","iconFallback","serviceUrl","endpoints"],"properties":{"provider":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"secondaryCategories":{"type":"array","items":{"type":"string"},"description":"Additional marketplace categories beyond the primary (Parse), so catalogs can file a provider under every category its marketplace lists it in."},"verified":{"type":"boolean"},"logoUrl":{"type":"string","format":"uri"},"iconFallback":{"type":"object","required":["type","text"],"properties":{"type":{"const":"monogram"},"text":{"type":"string","minLength":1}},"additionalProperties":false},"serviceUrl":{"type":"string","format":"uri"},"websiteUrl":{"type":"string","format":"uri"},"docsUrl":{"type":"string","format":"uri"},"catalogPriority":{"type":"integer"},"catalogIdentity":{"type":"string"},"attribution":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"websiteUrl":{"type":"string","format":"uri"},"logoUrl":{"type":"string","format":"uri"}},"additionalProperties":false},"marketplaceRank":{"type":"integer"},"marketplaceFeatured":{"type":"boolean"},"externalRail":{"type":"string","enum":["mpp","x402"]},"availability":{"type":"string","enum":["available","temporarily_unavailable","unknown"],"description":"Current platform readiness. Omitted from compact agent projections."},"unavailableReason":{"type":["string","null"],"enum":["delivery_breaker","platform_pause",null]},"modelCatalog":{"$ref":"#/components/schemas/InferenceModelCatalog"},"endpoints":{"type":"array","items":{"$ref":"#/components/schemas/CatalogEndpoint"}}},"additionalProperties":false},"CompactCatalogProvider":{"type":"object","required":["provider","iconFallback","serviceUrl","endpoints"],"properties":{"provider":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"secondaryCategories":{"type":"array","items":{"type":"string"},"description":"Additional marketplace categories beyond the primary (Parse), so catalogs can file a provider under every category its marketplace lists it in."},"verified":{"type":"boolean"},"logoUrl":{"type":"string","format":"uri"},"iconFallback":{"type":"object","required":["type","text"],"properties":{"type":{"const":"monogram"},"text":{"type":"string","minLength":1}},"additionalProperties":false},"serviceUrl":{"type":"string","format":"uri"},"websiteUrl":{"type":"string","format":"uri"},"docsUrl":{"type":"string","format":"uri"},"catalogPriority":{"type":"integer"},"catalogIdentity":{"type":"string"},"attribution":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"websiteUrl":{"type":"string","format":"uri"},"logoUrl":{"type":"string","format":"uri"}},"additionalProperties":false},"marketplaceRank":{"type":"integer"},"marketplaceFeatured":{"type":"boolean"},"externalRail":{"type":"string","enum":["mpp","x402"]},"endpoints":{"type":"array","items":{"$ref":"#/components/schemas/CompactCatalogEndpoint"}}},"additionalProperties":false},"CatalogEndpoint":{"type":"object","required":["slug","method","inputSchema","inputExample","dynamic","enabled","markupBps","overridden","markupSource","flatSource","flatMarkupUsdc","flatMarkupUsd","baseUsdc","chargedUsdc","effectiveUsd","marginUsdc","baseCredits","effectiveCredits","marginCredits"],"properties":{"slug":{"type":"string"},"method":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"estimatedCost":{"type":"string"},"billingModel":{"type":"string","enum":["usage","prepaid_runtime"],"description":"Variable charge collection model; omitted for ordinary fixed-price actions."},"inputSchema":{"type":"object","description":"The same usable JSON Schema published by MCP tools/list for this endpoint."},"inputExample":{"type":"object","description":"Canonical example arguments accepted by inputSchema."},"dynamic":{"type":"boolean"},"enabled":{"type":"boolean"},"availability":{"type":"string","enum":["available","temporarily_unavailable","unknown"],"description":"Current platform readiness. This is separate from tenant enablement."},"unavailableReason":{"type":["string","null"],"enum":["delivery_breaker","platform_pause",null]},"systemManaged":{"const":true,"description":"Present for virtual capability-router endpoints that ordinary catalog controls cannot disable."},"route":{"type":"string","description":"Exact execution route for a system-managed capability."},"previewRoute":{"type":"string","description":"No-dispatch estimate route for a system-managed capability."},"markupBps":{"type":"integer"},"overridden":{"type":"boolean"},"markupSource":{"type":"string","enum":["endpoint","provider","global"]},"flatSource":{"type":"string","enum":["endpoint","provider","global"]},"flatMarkupUsdc":{"$ref":"#/components/schemas/DecimalString"},"flatMarkupUsd":{"$ref":"#/components/schemas/DecimalString"},"baseUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"chargedUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"effectiveUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"marginUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"baseCredits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"effectiveCredits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"marginCredits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]}},"additionalProperties":false},"CompactCatalogEndpoint":{"type":"object","required":["slug","method","dynamic","enabled","markupBps","overridden","markupSource","flatSource","flatMarkupUsdc","flatMarkupUsd","baseUsdc","chargedUsdc","effectiveUsd","marginUsdc","baseCredits","effectiveCredits","marginCredits"],"properties":{"slug":{"type":"string"},"method":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"estimatedCost":{"type":"string"},"billingModel":{"type":"string","enum":["usage","prepaid_runtime"],"description":"Variable charge collection model; omitted for ordinary fixed-price actions."},"dynamic":{"type":"boolean"},"enabled":{"type":"boolean"},"systemManaged":{"const":true,"description":"Present for virtual capability-router endpoints that ordinary catalog controls cannot disable."},"route":{"type":"string","description":"Exact execution route for a system-managed capability."},"previewRoute":{"type":"string","description":"No-dispatch estimate route for a system-managed capability."},"markupBps":{"type":"integer"},"overridden":{"type":"boolean"},"markupSource":{"type":"string","enum":["endpoint","provider","global"]},"flatSource":{"type":"string","enum":["endpoint","provider","global"]},"flatMarkupUsdc":{"$ref":"#/components/schemas/DecimalString"},"flatMarkupUsd":{"$ref":"#/components/schemas/DecimalString"},"baseUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"chargedUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"effectiveUsd":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"marginUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"baseCredits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"effectiveCredits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"marginCredits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]}},"additionalProperties":false},"SignedDecimalString":{"type":"string","pattern":"^-?\\d+(?:\\.\\d{1,6})?$","description":"Exact signed USD decimal string with at most six fractional digits."},"WebhookVerification":{"type":"object","required":["id","destinationUrl","status","attempts","scheduledAt","verifiedAt","error"],"properties":{"id":{"type":"string","format":"uuid"},"destinationUrl":{"type":"string","format":"uri"},"status":{"type":"string","enum":["pending","verifying","verified","failed","superseded"]},"attempts":{"type":"integer","minimum":0,"maximum":5},"scheduledAt":{"type":"string","format":"date-time"},"verifiedAt":{"type":["string","null"],"format":"date-time"},"error":{"type":["string","null"]}},"additionalProperties":false},"WebhookEventType":{"type":"string","enum":["credits.topup.completed","credits.topup.failed","credits.burn.completed","credits.burn.failed","credits.refund.issued","credits.dispute.opened","credits.dispute.closed","credits.balance.changed","credits.balance.low","credits.account.frozen","credits.usage_drift.detected","credits.usage_drift.resolved"]},"WebhookTopupCompletedData":{"type":"object","required":["externalUserId","amountUsd","balanceUsd","reference","source","metadata"],"properties":{"externalUserId":{"type":["string","null"]},"amountUsd":{"$ref":"#/components/schemas/DecimalString"},"balanceUsd":{"$ref":"#/components/schemas/DecimalString"},"reference":{"type":"string"},"source":{"type":"string","enum":["checkout_session","auto_recharge"]},"bonusUsd":{"$ref":"#/components/schemas/DecimalString","description":"Volume bonus minted alongside this top-up (pool purchases only). Present only when a bonus was actually granted; balanceUsd then reflects the post-bonus balance."},"metadata":{"oneOf":[{"type":"object","additionalProperties":{"type":"string"}},{"type":"null"}]}},"additionalProperties":false},"WebhookTopupFailedData":{"type":"object","required":["externalUserId","reason","reference"],"properties":{"externalUserId":{"type":["string","null"]},"reason":{"type":"string"},"reference":{"type":"string"},"paymentIntentId":{"type":"string"}},"additionalProperties":false},"WebhookBurnCompletedData":{"type":"object","required":["apiCallId","provider","endpoint","amountUsd","balanceUsd","mode","externalUserId"],"properties":{"apiCallId":{"type":"string"},"provider":{"type":"string"},"endpoint":{"type":"string"},"amountUsd":{"$ref":"#/components/schemas/DecimalString"},"balanceUsd":{"$ref":"#/components/schemas/DecimalString"},"mode":{"type":"string","enum":["platform","end_user"]},"externalUserId":{"type":["string","null"]}},"additionalProperties":false},"WebhookBurnFailedData":{"type":"object","required":["apiCallId","provider","endpoint","amountUsd","mode","externalUserId","reason"],"properties":{"apiCallId":{"type":"string"},"provider":{"type":"string"},"endpoint":{"type":"string"},"amountUsd":{"$ref":"#/components/schemas/DecimalString"},"mode":{"type":"string","enum":["platform","end_user"]},"externalUserId":{"type":["string","null"]},"reason":{"type":"string"}},"additionalProperties":false},"WebhookRefundIssuedData":{"oneOf":[{"type":"object","required":["apiCallId","reference","provider","endpoint","amountUsd","mode","externalUserId","reason"],"properties":{"apiCallId":{"type":"string"},"reference":{"type":"string"},"provider":{"type":"string"},"endpoint":{"type":"string"},"amountUsd":{"$ref":"#/components/schemas/DecimalString"},"mode":{"type":"string","enum":["platform","end_user"]},"externalUserId":{"type":["string","null"]},"reason":{"const":"upstream_failure"}},"additionalProperties":false},{"type":"object","required":["externalUserId","amountUsd","reason","reference"],"properties":{"externalUserId":{"type":["string","null"]},"amountUsd":{"$ref":"#/components/schemas/DecimalString"},"reason":{"const":"account_frozen"},"reference":{"type":"string"}},"additionalProperties":false},{"type":"object","required":["accountId","chargeId","amountUsd","marginClawbackUsd","cumulativeRefundedCents","reason","reference"],"properties":{"accountId":{"type":"string"},"chargeId":{"type":"string"},"amountUsd":{"$ref":"#/components/schemas/DecimalString"},"marginClawbackUsd":{"$ref":"#/components/schemas/DecimalString"},"bonusClawbackUsd":{"$ref":"#/components/schemas/DecimalString","description":"Volume-bonus credits clawed back alongside the principal. Present only when the refunded top-up had earned a bonus."},"cumulativeRefundedCents":{"type":"integer","minimum":0},"reason":{"const":"stripe_refund"},"reference":{"type":"string"}},"additionalProperties":false},{"type":"object","required":["externalUserId","amountUsd","reason","reference"],"properties":{"externalUserId":{"type":["string","null"]},"amountUsd":{"$ref":"#/components/schemas/DecimalString"},"reason":{"const":"funding_unavailable"},"reference":{"type":"string"}},"additionalProperties":false}]},"WebhookDisputeOpenedData":{"type":"object","required":["accountId","disputeId","amountUsd","clawbackUsd","marginClawbackUsd","status"],"properties":{"accountId":{"type":"string"},"disputeId":{"type":"string"},"amountUsd":{"$ref":"#/components/schemas/DecimalString"},"clawbackUsd":{"$ref":"#/components/schemas/DecimalString"},"marginClawbackUsd":{"$ref":"#/components/schemas/DecimalString"},"bonusClawbackUsd":{"$ref":"#/components/schemas/DecimalString","description":"Volume-bonus credits clawed alongside the principal. Present only when the disputed top-up had earned a bonus."},"status":{"type":"string"}},"additionalProperties":false},"WebhookDisputeClosedData":{"type":"object","required":["accountId","disputeId","outcome"],"properties":{"accountId":{"type":["string","null"]},"disputeId":{"type":"string"},"outcome":{"type":"string"}},"additionalProperties":false},"WebhookBalanceChangedData":{"type":"object","required":["reference","externalUserId","deltaUsd","balanceUsd","reason"],"properties":{"apiCallId":{"type":"string"},"reference":{"type":"string"},"externalUserId":{"type":["string","null"]},"deltaUsd":{"$ref":"#/components/schemas/SignedDecimalString"},"balanceUsd":{"$ref":"#/components/schemas/DecimalString"},"reason":{"type":"string","enum":["topup","burn","refund","dispute_reversal","allocate","deallocate","expiration"]}},"additionalProperties":false},"WebhookBalanceLowData":{"type":"object","required":["reason"],"properties":{"balanceUsd":{"$ref":"#/components/schemas/DecimalString"},"thresholdUsd":{"$ref":"#/components/schemas/DecimalString"},"reason":{"type":"string"},"paymentIntentId":{"type":"string"}},"additionalProperties":false},"WebhookAccountFrozenData":{"type":"object","required":["accountId","disputeId","reason"],"properties":{"accountId":{"type":"string"},"disputeId":{"type":"string"},"reason":{"const":"dispute_opened"}},"additionalProperties":false},"WebhookEventEnvelope":{"type":"object","required":["id","type","api_version","created_at","sequence","tenant_id","data"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"$ref":"#/components/schemas/WebhookEventType"},"api_version":{"const":"2026-08-13"},"created_at":{"type":"string","format":"date-time"},"sequence":{"type":"string","pattern":"^\\d+$"},"tenant_id":{"type":"string","format":"uuid"},"data":{"oneOf":[{"$ref":"#/components/schemas/WebhookTopupCompletedData"},{"$ref":"#/components/schemas/WebhookTopupFailedData"},{"$ref":"#/components/schemas/WebhookBurnCompletedData"},{"$ref":"#/components/schemas/WebhookBurnFailedData"},{"$ref":"#/components/schemas/WebhookRefundIssuedData"},{"$ref":"#/components/schemas/WebhookDisputeOpenedData"},{"$ref":"#/components/schemas/WebhookDisputeClosedData"},{"$ref":"#/components/schemas/WebhookBalanceChangedData"},{"$ref":"#/components/schemas/WebhookBalanceLowData"},{"$ref":"#/components/schemas/WebhookAccountFrozenData"}]}}},"WebhookDelivery":{"type":"object","required":["id","attempt","destination_url","status","manual_replay","scheduled_at"],"properties":{"id":{"type":"string","format":"uuid"},"attempt":{"type":"integer","minimum":1},"destination_url":{"type":"string","format":"uri"},"status":{"type":"string","enum":["pending","delivering","delivered","failed"]},"manual_replay":{"type":"boolean"},"scheduled_at":{"type":"string","format":"date-time"},"started_at":{"type":["string","null"],"format":"date-time"},"finished_at":{"type":["string","null"],"format":"date-time"},"http_status":{"type":["integer","null"]},"response_body":{"type":["string","null"],"maxLength":1024},"error":{"type":["string","null"]}}},"WebhookEventPage":{"type":"object","required":["success","data","next_cursor"],"properties":{"success":{"const":true},"data":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/WebhookEventEnvelope"},{"type":"object","required":["retained_until","delivery"],"properties":{"retained_until":{"type":"string","format":"date-time"},"delivery":{"oneOf":[{"$ref":"#/components/schemas/WebhookDelivery"},{"type":"null"}]}}}]}},"next_cursor":{"type":["string","null"],"format":"uuid"}}},"WebhookEventDetail":{"type":"object","required":["success","event"],"properties":{"success":{"const":true},"event":{"allOf":[{"$ref":"#/components/schemas/WebhookEventEnvelope"},{"type":"object","required":["retained_until","deliveries"],"properties":{"retained_until":{"type":"string","format":"date-time"},"deliveries":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}}}}]}}},"AnalyticsSummary":{"type":"object","required":["usageUsdc","baseUsdc","marginUsdc","calls","activeUsers"],"properties":{"usageUsdc":{"$ref":"#/components/schemas/DecimalString"},"baseUsdc":{"$ref":"#/components/schemas/DecimalString"},"marginUsdc":{"$ref":"#/components/schemas/DecimalString"},"calls":{"type":"integer","minimum":0},"activeUsers":{"type":"integer","minimum":0}},"additionalProperties":false},"AnalyticsDay":{"type":"object","additionalProperties":false,"required":["date","usageUsdc","baseUsdc","marginUsdc","calls","activeUsers"],"properties":{"date":{"type":"string","format":"date"},"usageUsdc":{"$ref":"#/components/schemas/DecimalString"},"baseUsdc":{"$ref":"#/components/schemas/DecimalString"},"marginUsdc":{"$ref":"#/components/schemas/DecimalString"},"calls":{"type":"integer","minimum":0},"activeUsers":{"type":"integer","minimum":0}}},"AnalyticsService":{"type":"object","additionalProperties":false,"required":["provider","endpoint","usageUsdc","baseUsdc","marginUsdc","calls","activeUsers","spenders"],"properties":{"provider":{"type":"string"},"endpoint":{"type":["string","null"]},"usageUsdc":{"$ref":"#/components/schemas/DecimalString"},"baseUsdc":{"$ref":"#/components/schemas/DecimalString"},"marginUsdc":{"$ref":"#/components/schemas/DecimalString"},"calls":{"type":"integer","minimum":0},"activeUsers":{"type":"integer","minimum":0,"description":"Distinct END USERS. Pooled agents, API keys and members have no end user, so an endpoint driven only by those reports zero here."},"spenders":{"type":"integer","minimum":0,"description":"Distinct spenders, the same population AnalyticsProvider.spenders counts."}}},"AnalyticsUser":{"type":"object","required":["externalUserId","usageUsdc","marginUsdc","calls"],"properties":{"externalUserId":{"oneOf":[{"$ref":"#/components/schemas/ExternalUserId"},{"type":"null"}]},"usageUsdc":{"$ref":"#/components/schemas/DecimalString"},"marginUsdc":{"$ref":"#/components/schemas/DecimalString"},"calls":{"type":"integer","minimum":0}},"additionalProperties":false},"UsageDriftDetection":{"type":"object","required":["id","feature","appVersion","status","severity","mode","coverageRatio","baselineSamples","currentSamples","requiredSamples","baseline","current","percentageChange","adjustedPValue","contributors","lastEvaluatedAt","ledgerFilterPath","informational"],"properties":{"id":{"type":"string","format":"uuid"},"feature":{"type":"string"},"appVersion":{"type":["string","null"]},"status":{"type":"string","enum":["SHADOW","ACTIVE","RESOLVED"]},"severity":{"type":"string","enum":["INFO","WARNING","CRITICAL"]},"mode":{"type":"string","enum":["shadow","enabled"]},"coverageRatio":{"$ref":"#/components/schemas/DecimalString"},"baselineSamples":{"type":"integer","minimum":0},"currentSamples":{"type":"integer","minimum":0},"requiredSamples":{"type":"integer","minimum":0},"baseline":{"type":"object"},"current":{"type":"object"},"percentageChange":{"type":["string","null"]},"adjustedPValue":{"type":["string","null"]},"contributors":{"type":"object"},"firstSeenAt":{"type":["string","null"],"format":"date-time"},"detectedAt":{"type":["string","null"],"format":"date-time"},"resolvedAt":{"type":["string","null"],"format":"date-time"},"lastEvaluatedAt":{"type":"string","format":"date-time"},"ledgerFilterPath":{"type":"string"},"informational":{"const":true}}},"UsageDriftAnalytics":{"type":"object","required":["mode","attributionCoverageRequired","currentWindowDays","baselineWindowDays","collecting","active","recentResolved"],"properties":{"mode":{"type":"string","enum":["shadow","enabled"]},"attributionCoverageRequired":{"$ref":"#/components/schemas/DecimalString"},"currentWindowDays":{"type":"integer"},"baselineWindowDays":{"type":"integer"},"collecting":{"type":"integer","minimum":0},"active":{"type":"array","items":{"$ref":"#/components/schemas/UsageDriftDetection"}},"recentResolved":{"type":"array","items":{"$ref":"#/components/schemas/UsageDriftDetection"}}},"additionalProperties":false},"AnalyticsBucket":{"type":"object","description":"One gap-filled series bucket.","additionalProperties":false,"required":["start","usageUsdc","baseUsdc","marginUsdc","calls","activeUsers"],"properties":{"start":{"type":"string","format":"date-time","description":"First instant of the bucket (UTC)."},"usageUsdc":{"$ref":"#/components/schemas/DecimalString"},"baseUsdc":{"$ref":"#/components/schemas/DecimalString"},"marginUsdc":{"$ref":"#/components/schemas/DecimalString"},"calls":{"type":"integer","minimum":0},"activeUsers":{"type":"integer","minimum":0}}},"AnalyticsProvider":{"type":"object","description":"Provider-level rollup: every endpoint of one provider folded together.","additionalProperties":false,"required":["provider","spenders","endpoints","usageUsdc","baseUsdc","marginUsdc","calls","activeUsers"],"properties":{"provider":{"type":"string"},"spenders":{"type":"integer","description":"Distinct spenders who used the provider."},"endpoints":{"type":"integer","description":"Distinct endpoints used; a provider-level burn with no endpoint counts as one."},"usageUsdc":{"$ref":"#/components/schemas/DecimalString"},"baseUsdc":{"$ref":"#/components/schemas/DecimalString"},"marginUsdc":{"$ref":"#/components/schemas/DecimalString"},"calls":{"type":"integer","minimum":0},"activeUsers":{"type":"integer","minimum":0}}},"AnalyticsInitiator":{"type":"object","additionalProperties":false,"required":["type","initiatorId","label","authMethod","clients","usageUsdc","marginUsdc","calls","providers"],"properties":{"type":{"type":"string","enum":["oauth_member","end_user","agent_connection","customer","credential","unattributed"]},"initiatorId":{"type":["string","null"]},"label":{"type":"string"},"authMethod":{"type":["string","null"]},"clients":{"type":"array","items":{"type":"string"}},"usageUsdc":{"type":"string"},"marginUsdc":{"type":"string"},"calls":{"type":"integer"},"providers":{"type":"integer","description":"Distinct providers this spender used in the current window."},"source":{"type":"string","description":"Customer rows only: the product (attribution.source; '' when the charges carried none)."},"customerId":{"type":"string","description":"Customer rows only: the tenant's own customer id. initiatorId is <URL-encoded source>/<customerId>."},"name":{"type":["string","null"],"description":"Customer rows only: the customer directory's name, null when unnamed. label is the name when there is one."},"url":{"type":["string","null"],"description":"Customer rows only: the directory's link for the customer."},"adminUrl":{"type":["string","null"],"description":"Customer rows only: the directory's link into the tenant's own admin for the customer."}}},"AnalyticsFilter":{"type":"object","additionalProperties":false,"description":"The filter the response was computed under, echoed back.","required":["initiator","provider","endpoint"],"properties":{"initiator":{"oneOf":[{"type":"object","additionalProperties":false,"required":["type","id"],"properties":{"type":{"type":"string","enum":["oauth_member","end_user","agent_connection","customer","credential","unattributed"]},"id":{"type":["string","null"]}}},{"type":"null"}]},"provider":{"type":["string","null"]},"endpoint":{"type":["string","null"]}}},"AnalyticsResponse":{"type":"object","required":["success","analytics"],"properties":{"success":{"const":true},"analytics":{"type":"object","required":["days","bucket","filter","timezone","periodStart","periodEndExclusive","priorPeriodStart","priorPeriodEndExclusive","summary","priorSummary","series","daily","services","providers","users","initiators","usageDrift"],"properties":{"days":{"type":["integer","null"],"enum":[7,30,90,null],"description":"Echo of the legacy form; null when the request used from/to."},"bucket":{"type":"string","enum":["hour","day","week","month"]},"filter":{"$ref":"#/components/schemas/AnalyticsFilter"},"timezone":{"const":"UTC"},"periodStart":{"type":"string","format":"date-time"},"periodEndExclusive":{"type":"string","format":"date-time"},"priorPeriodStart":{"type":"string","format":"date-time"},"priorPeriodEndExclusive":{"type":"string","format":"date-time"},"summary":{"$ref":"#/components/schemas/AnalyticsSummary"},"priorSummary":{"$ref":"#/components/schemas/AnalyticsSummary"},"series":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsBucket"}},"daily":{"type":"array","description":"series relabelled by the UTC day of each bucket start; identical to series when bucket is day.","items":{"$ref":"#/components/schemas/AnalyticsDay"}},"services":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsService"}},"providers":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsProvider"}},"users":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsUser"}},"initiators":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsInitiator"}},"customerSources":{"type":"array","description":"Spend per product over every customer burn in the window (not only the ranked ones), under the same filter.","items":{"$ref":"#/components/schemas/AnalyticsCustomerSource"}},"usageDrift":{"oneOf":[{"$ref":"#/components/schemas/UsageDriftAnalytics"},{"type":"null"}]}},"additionalProperties":false}},"additionalProperties":false},"EndUserCatalogEndpoint":{"type":"object","additionalProperties":false,"required":["id","slug","displayName","description","enabled","price"],"properties":{"id":{"type":"string","description":"Stable public endpoint ID"},"slug":{"type":"string","example":"tavily/search"},"displayName":{"type":"string","example":"Search"},"description":{"type":"string","description":"Price- and policy-neutral endpoint description"},"enabled":{"type":"boolean","const":true},"price":{"$ref":"#/components/schemas/EndUserCatalogPrice"}}},"EndUserCatalogPrice":{"oneOf":[{"type":"object","additionalProperties":false,"required":["state","credits","usd"],"properties":{"state":{"type":"string","const":"exact"},"credits":{"type":"string"},"usd":{"type":"string","description":"Final customer-visible effective USD price; never base cost"}}},{"type":"object","additionalProperties":false,"required":["state"],"properties":{"state":{"type":"string","enum":["dynamic","unavailable"]}}}]},"EndUserCatalogProvider":{"type":"object","additionalProperties":false,"required":["id","slug","displayName","category","description","logoUrl","enabled","endpoints"],"properties":{"id":{"type":"string","description":"Stable public provider ID"},"slug":{"type":"string"},"displayName":{"type":"string"},"category":{"type":"string"},"description":{"type":"string"},"logoUrl":{"type":"string","format":"uri","description":"Absolute stable brand-asset URL"},"enabled":{"type":"boolean","const":true},"endpoints":{"type":"array","items":{"$ref":"#/components/schemas/EndUserCatalogEndpoint"}}}},"EndUserCatalogResponse":{"type":"object","additionalProperties":false,"required":["success","version","providers","nextCursor"],"properties":{"success":{"type":"boolean","const":true},"version":{"type":"string","const":"2026-08-14"},"providers":{"type":"array","items":{"$ref":"#/components/schemas/EndUserCatalogProvider"}},"nextCursor":{"type":["string","null"]}}},"LedgerEntry":{"type":"object","additionalProperties":false,"required":["id","direction","category","amountUsdc","amountCredits","balanceAfterUsdc","baseUsdc","marginUsdc","markupBps","sourceKey","externalReference","externalUserId","metadata","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["DEBIT","CREDIT"]},"category":{"type":"string"},"amountUsdc":{"$ref":"#/components/schemas/DecimalString"},"amountCredits":{"$ref":"#/components/schemas/DecimalString"},"balanceAfterUsdc":{"$ref":"#/components/schemas/DecimalString"},"baseUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"marginUsdc":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"markupBps":{"type":["integer","null"]},"sourceKey":{"type":"string"},"externalReference":{"type":["string","null"]},"externalUserId":{"type":["string","null"]},"metadata":{},"createdAt":{"type":"string","format":"date-time"}}},"LedgerPage":{"type":"object","additionalProperties":false,"required":["success","entries","nextCursor"],"properties":{"success":{"type":"boolean","const":true},"entries":{"type":"array","items":{"$ref":"#/components/schemas/LedgerEntry"}},"nextCursor":{"type":["string","null"]}}},"AppliedLedgerFilters":{"type":"array","description":"Names of the narrowing query filters this server applied. An empty array means the request did not include a narrowing filter.","items":{"type":"string","enum":["account","attribution","category","createdAfter","createdBefore","endpoint","externalUserId","initiator","provider","sourceKey"]},"uniqueItems":true},"TenantLedgerPage":{"type":"object","additionalProperties":false,"required":["success","entries","nextCursor","customers","appliedFilters"],"properties":{"success":{"type":"boolean","const":true},"entries":{"type":"array","items":{"$ref":"#/components/schemas/LedgerEntry"}},"nextCursor":{"type":["string","null"]},"customers":{"type":"array","description":"Directory names for the customers this page's entries were attributed to.","items":{"$ref":"#/components/schemas/CustomerName"}},"appliedFilters":{"$ref":"#/components/schemas/AppliedLedgerFilters"}}},"TenantLedgerSummary":{"type":"object","additionalProperties":false,"required":["success","total","byCategory","amountUsdcByCategory","appliedFilters"],"properties":{"success":{"type":"boolean","const":true},"total":{"type":"integer"},"byCategory":{"type":"object","description":"Counts keyed by ledger category; categories with no rows are absent.","additionalProperties":{"type":"integer"}},"amountUsdcByCategory":{"type":"object","description":"Unsigned USDC magnitude keyed by ledger category, over the same rows (direction carries the sign). Analytics covers BURN rows only, so a refund total for the same filters comes from here.","additionalProperties":{"$ref":"#/components/schemas/DecimalString"}},"appliedFilters":{"$ref":"#/components/schemas/AppliedLedgerFilters"}}},"EndUserPolicyInput":{"type":"object","required":["mode"],"properties":{"mode":{"type":"string","enum":["ask","bounded","unlimited"]},"budgetPeriod":{"type":["string","null"],"enum":["hour","day","week","month",null]},"budgetCredits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"maxChargeCredits":{"oneOf":[{"$ref":"#/components/schemas/DecimalString"},{"type":"null"}]},"allowProviders":{"type":["array","null"],"items":{"type":"string"},"maxItems":200},"denyProviders":{"type":["array","null"],"items":{"type":"string"},"maxItems":200},"allowEndpoints":{"type":["array","null"],"items":{"type":"string","description":"provider/endpoint"},"maxItems":200},"denyEndpoints":{"type":["array","null"],"items":{"type":"string","description":"provider/endpoint"},"maxItems":200},"allowModels":{"type":["array","null"],"items":{"type":"string"},"maxItems":200},"denyModels":{"type":["array","null"],"items":{"type":"string"},"maxItems":200},"maxConcurrentReservations":{"type":["integer","null"],"minimum":1,"maximum":1000000},"maxCallsPerPeriod":{"type":["integer","null"],"minimum":1,"maximum":1000000},"maxCallsPerLoop":{"type":["integer","null"],"minimum":1,"maximum":1000000}},"additionalProperties":false},"EndUserPolicy":{"allOf":[{"$ref":"#/components/schemas/EndUserPolicyInput"},{"type":"object","required":["id","activeReservations","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"activeReservations":{"type":"integer","minimum":0},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}]},"EndUserPolicyEnvelope":{"type":"object","required":["success","externalUserId","policy"],"properties":{"success":{"const":true},"externalUserId":{"$ref":"#/components/schemas/ExternalUserId"},"policy":{"oneOf":[{"$ref":"#/components/schemas/EndUserPolicy"},{"type":"null"}]}}},"EndUserPolicyEvent":{"type":"object","required":["id","policyId","accountId","action","reasonCode","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"policyId":{"type":"string","format":"uuid"},"accountId":{"type":"string","format":"uuid"},"reservationId":{"type":["string","null"],"format":"uuid"},"action":{"type":"string","enum":["ALLOW","DENY","CAPTURE","RELEASE"]},"reasonCode":{"type":"string","description":"Stable POLICY_* denial code or lifecycle reason."},"amountUsdc":{"type":["string","null"]},"amountCredits":{"type":["string","null"]},"idempotencyKey":{"type":["string","null"]},"metadata":{"type":["object","null"],"additionalProperties":true},"createdAt":{"type":"string","format":"date-time"}}},"OpenAIChatCompletionRequest":{"type":"object","required":["model","messages"],"properties":{"model":{"type":"string"},"messages":{"type":"array","minItems":1,"items":{"type":"object","additionalProperties":true}},"stream":{"type":"boolean","default":false},"stream_options":{"type":"object","additionalProperties":true},"max_tokens":{"type":"integer","minimum":1},"max_completion_tokens":{"type":"integer","minimum":1,"description":"For reviewed reasoning models, an explicit value must be at least that model's recommendedMinOutputTokens (currently 4000); smaller budgets are rejected before dispatch or billing because hidden reasoning can exhaust the budget before visible output."},"tools":{"type":"array","items":{"type":"object","additionalProperties":true}},"tool_choice":{}},"additionalProperties":true},"CreditsCallStatus":{"type":"object","required":["apiCallId","status","provider","endpoint","stream","billing","createdAt"],"properties":{"apiCallId":{"type":"string","format":"uuid"},"status":{"type":"string"},"provider":{"type":"string"},"endpoint":{"type":"string"},"stream":{"oneOf":[{"type":"null"},{"type":"object","required":["state","contentType"],"properties":{"state":{"type":"string","enum":["streaming","completed","client_disconnected","upstream_error","settlement_pending"]},"contentType":{"type":"string"},"error":{"type":"string"}}}]},"billing":{"type":"object","required":["chargedCredits","balanceCredits","settlement"],"properties":{"chargedCredits":{"$ref":"#/components/schemas/DecimalString"},"balanceCredits":{"$ref":"#/components/schemas/DecimalString"},"reservedCredits":{"$ref":"#/components/schemas/DecimalString","description":"Hold still reserved while a stream is being delivered."},"settlement":{"type":"string","enum":["settled-after-delivery","standard"]}}},"error":{"type":["string","null"]},"errorStage":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"completedAt":{"type":["string","null"],"format":"date-time"}}},"CustomerRef":{"type":"object","additionalProperties":false,"required":["customerId"],"properties":{"source":{"type":"string","maxLength":128,"default":"","description":"attribution.source; '' or omitted for charges tagged without one."},"customerId":{"type":"string","minLength":1,"maxLength":256}}},"CustomerUpsert":{"type":"object","additionalProperties":false,"required":["customerId","name"],"properties":{"source":{"type":"string","maxLength":128,"default":""},"customerId":{"type":"string","minLength":1,"maxLength":256},"name":{"type":"string","minLength":1,"maxLength":120,"description":"Trimmed; no control characters."},"url":{"type":["string","null"],"maxLength":512,"format":"uri","description":"Absolute http(s) URL, stored exactly as sent."},"adminUrl":{"type":["string","null"],"maxLength":512,"format":"uri","description":"Absolute http(s) URL, stored exactly as sent."}}},"CustomerDirectoryEntry":{"type":"object","additionalProperties":false,"required":["source","customerId","name","url","adminUrl","updatedAt"],"properties":{"source":{"type":"string"},"customerId":{"type":"string"},"name":{"type":"string"},"url":{"type":["string","null"]},"adminUrl":{"type":["string","null"]},"updatedAt":{"type":"string","format":"date-time"}}},"CustomerName":{"type":"object","additionalProperties":false,"required":["spenderId","source","customerId","name","url","adminUrl"],"properties":{"spenderId":{"type":"string","description":"The customer's spender id: <URL-encoded source>/<customerId>."},"source":{"type":"string"},"customerId":{"type":"string"},"name":{"type":"string"},"url":{"type":["string","null"]},"adminUrl":{"type":["string","null"]}}},"CustomerSpend":{"type":"object","additionalProperties":false,"required":["spenderId","source","customerId","name","url","adminUrl","usageUsdc","calls","providers","firstChargeAt","lastChargeAt"],"properties":{"spenderId":{"type":"string","description":"<URL-encoded source>/<customerId>; focuses analytics as initiator=customer:<spenderId>."},"source":{"type":"string"},"customerId":{"type":"string"},"name":{"type":["string","null"]},"url":{"type":["string","null"]},"adminUrl":{"type":["string","null"]},"usageUsdc":{"type":"string"},"calls":{"type":"integer"},"providers":{"type":"integer"},"firstChargeAt":{"type":"string","format":"date-time"},"lastChargeAt":{"type":"string","format":"date-time"}}},"AnalyticsCustomerSource":{"type":"object","additionalProperties":false,"required":["source","customers","usageUsdc","calls"],"properties":{"source":{"type":"string"},"customers":{"type":"integer"},"usageUsdc":{"type":"string"},"calls":{"type":"integer"}}},"EndUserAccount":{"type":"object","required":["externalUserId","accountId","balanceUsdc","balanceCredits","status","createdAt"],"properties":{"externalUserId":{"$ref":"#/components/schemas/ExternalUserId"},"accountId":{"type":"string","format":"uuid"},"balanceUsdc":{"$ref":"#/components/schemas/DecimalString"},"balanceCredits":{"$ref":"#/components/schemas/DecimalString"},"status":{"type":"string","enum":["active","frozen"]},"createdAt":{"type":"string","format":"date-time"}},"additionalProperties":false}}}}
