58445dd880
Load users by registration order, expose consumed and current credits, and accept short internal IDs so support can reliably locate accounts.
1427 lines
50 KiB
YAML
1427 lines
50 KiB
YAML
openapi: 3.1.0
|
|
info:
|
|
title: OSG Account Server API
|
|
version: 0.1.0
|
|
description: |
|
|
Account, credit, referral, integrity, and managed AI APIs for OSGKeyboard.
|
|
Local features and user-owned API keys remain independent of this service.
|
|
servers:
|
|
- url: https://account.osglab.com
|
|
security:
|
|
- bearerAuth: []
|
|
paths:
|
|
/health:
|
|
get:
|
|
security: []
|
|
summary: Compatibility health check
|
|
responses:
|
|
"200": { $ref: "#/components/responses/HealthUp" }
|
|
/health/live:
|
|
get:
|
|
security: []
|
|
summary: Process liveness
|
|
responses:
|
|
"200": { $ref: "#/components/responses/HealthUp" }
|
|
/health/ready:
|
|
get:
|
|
security: []
|
|
summary: Database and migration readiness
|
|
responses:
|
|
"200": { $ref: "#/components/responses/HealthUp" }
|
|
"503":
|
|
description: Database is unavailable or migrations failed.
|
|
/v1/auth/apple:
|
|
post:
|
|
security: []
|
|
summary: Exchange Sign in with Apple credentials for an OSG session
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AppleSignInRequest" }
|
|
responses:
|
|
"200":
|
|
description: Authenticated session
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/SessionTokenEnvelope" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/auth/refresh:
|
|
post:
|
|
security: []
|
|
summary: Rotate a refresh token
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [refreshToken]
|
|
properties:
|
|
refreshToken: { type: string, minLength: 32 }
|
|
responses:
|
|
"200":
|
|
description: Rotated session
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/SessionTokenEnvelope" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/auth/logout:
|
|
post:
|
|
summary: Revoke the current session family
|
|
responses:
|
|
"204": { description: Session revoked }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/account:
|
|
get:
|
|
summary: Return the account profile
|
|
responses:
|
|
"200":
|
|
description: Account profile
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AccountEnvelope" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
patch:
|
|
summary: Update the current account nickname
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/UpdateAccountProfileRequest" }
|
|
responses:
|
|
"200":
|
|
description: Updated account profile
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AccountEnvelope" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
delete:
|
|
summary: Reauthenticate with Apple, delete the account, and revoke authorization
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/DeleteAccountRequest" }
|
|
responses:
|
|
"204": { description: Account deleted }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/apple/events:
|
|
post:
|
|
security: []
|
|
summary: Receive a signed Apple server-to-server account event
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [payload]
|
|
properties:
|
|
payload: { type: string }
|
|
responses:
|
|
"204": { description: Event accepted }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/credits/balance:
|
|
get:
|
|
summary: Return available and consumed integer credits
|
|
responses:
|
|
"200":
|
|
description: Credit account
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/CreditAccount" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/credits/ledger:
|
|
get:
|
|
summary: Return immutable credit history
|
|
parameters:
|
|
- $ref: "#/components/parameters/Limit"
|
|
responses:
|
|
"200":
|
|
description: Ledger entries
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/LedgerEntry" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/credits/rates:
|
|
get:
|
|
summary: Return effective managed-provider rate cards
|
|
responses:
|
|
"200":
|
|
description: Effective rate cards
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { type: object, additionalProperties: true }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/storekit/products:
|
|
get:
|
|
summary: Return enabled consumable credit products
|
|
description: |
|
|
Current catalog: `500tks` grants 500 credits, `1500tks` grants 1,500
|
|
credits, and `3000tks` grants 3,000 credits. Localized prices are
|
|
supplied by StoreKit.
|
|
responses:
|
|
"200":
|
|
description: StoreKit credit product catalog
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/StoreKitProduct" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/storekit/transactions:
|
|
post:
|
|
summary: Verify an App Store transaction and idempotently grant credits
|
|
description: |
|
|
Submit the StoreKit 2 `VerificationResult.jwsRepresentation` before
|
|
finishing the consumable transaction. The purchase must include an
|
|
`appAccountToken` equal to the authenticated account UUID. Replaying
|
|
the same App Store transaction returns the original grant.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/StoreKitTransactionRequest" }
|
|
responses:
|
|
"200":
|
|
description: Verified purchase grant or idempotent replay
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/StoreKitPurchase" }
|
|
"409": { $ref: "#/components/responses/Error" }
|
|
"422": { $ref: "#/components/responses/Error" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/referrals:
|
|
get:
|
|
summary: List invitees without exposing their Apple identity
|
|
parameters:
|
|
- $ref: "#/components/parameters/Limit"
|
|
responses:
|
|
"200":
|
|
description: Referral bindings
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items: { type: object, additionalProperties: true }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/referrals/me:
|
|
get:
|
|
summary: Return the referral profile and idempotently provision its invite code
|
|
responses:
|
|
"200":
|
|
description: Referral profile
|
|
content:
|
|
application/json:
|
|
schema: { type: object, additionalProperties: true }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/referrals/code:
|
|
post:
|
|
summary: Idempotently create the current campaign invite code
|
|
responses:
|
|
"200":
|
|
description: Invite code
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/ReferralCode" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/referrals/redeem:
|
|
post:
|
|
summary: Bind the account to an inviter during the eligibility window
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/RedeemReferralRequest" }
|
|
responses:
|
|
"200": { description: Referral binding }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/referrals/bind:
|
|
post:
|
|
deprecated: true
|
|
summary: Compatibility alias for referral redemption
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/RedeemReferralRequest" }
|
|
responses:
|
|
"200": { description: Referral binding }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/referrals/campaigns:
|
|
get:
|
|
summary: Return active referral campaigns
|
|
responses:
|
|
"200": { description: Active campaigns }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/integrity/challenges:
|
|
post:
|
|
security: []
|
|
summary: Issue a single-use App Attest challenge
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AppAttestChallengeRequest" }
|
|
responses:
|
|
"201":
|
|
description: Challenge issued
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AppAttestChallengeResponse" }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/integrity/attest:
|
|
post:
|
|
security: []
|
|
summary: Register a validated App Attest key
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AppAttestationRequest" }
|
|
responses:
|
|
"204": { description: Key registered }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/integrity/assert:
|
|
post:
|
|
security: []
|
|
summary: Validate a challenge-only App Attest assertion
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AppAssertionRequest" }
|
|
responses:
|
|
"200": { description: Assertion counter advanced }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/gateway/catalog:
|
|
get:
|
|
summary: Return configured managed-provider capabilities
|
|
responses:
|
|
"200": { description: Provider catalog }
|
|
default: { $ref: "#/components/responses/Error" }
|
|
/v1/gateway/grants:
|
|
post:
|
|
summary: Create an idempotent managed-provider grant
|
|
parameters:
|
|
- $ref: "#/components/parameters/IdempotencyKey"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/CreateGatewayGrantRequest" }
|
|
responses:
|
|
"201":
|
|
description: Gateway grant and rotating credentials
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/GatewayGrantTokens" }
|
|
default: { $ref: "#/components/responses/GatewayError" }
|
|
/v1/gateway/grants/refresh:
|
|
post:
|
|
security: []
|
|
summary: Rotate a gateway refresh token
|
|
parameters:
|
|
- $ref: "#/components/parameters/IdempotencyKey"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/RefreshGatewayGrantRequest" }
|
|
responses:
|
|
"200":
|
|
description: Rotated gateway credentials
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/GatewayGrantTokens" }
|
|
default: { $ref: "#/components/responses/GatewayError" }
|
|
/v1/gateway/grants/{grantId}:
|
|
delete:
|
|
summary: Revoke a gateway grant
|
|
parameters:
|
|
- name: grantId
|
|
in: path
|
|
required: true
|
|
schema: { type: string, format: uuid }
|
|
responses:
|
|
"204": { description: Gateway grant revoked }
|
|
default: { $ref: "#/components/responses/GatewayError" }
|
|
/v1/gateway/llm/{capability}:
|
|
post:
|
|
summary: Run a metered polish, AI, or agent request
|
|
parameters:
|
|
- $ref: "#/components/parameters/RequestId"
|
|
- name: capability
|
|
in: path
|
|
required: true
|
|
schema: { type: string, enum: [polish, ai, agent] }
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/TextGatewayRequest" }
|
|
responses:
|
|
"200":
|
|
description: JSON response, or SSE when stream is true
|
|
default: { $ref: "#/components/responses/GatewayError" }
|
|
/v1/gateway/asr:
|
|
post:
|
|
summary: Run buffered metered ASR
|
|
parameters:
|
|
- $ref: "#/components/parameters/RequestId"
|
|
- { name: X-Audio-Duration-Ms, in: header, required: true, schema: { type: integer, minimum: 1, maximum: 600000 } }
|
|
- { name: X-Audio-Format, in: header, schema: { type: string, enum: [pcm, wav, ogg, mp3], default: pcm } }
|
|
- { name: X-Audio-Codec, in: header, schema: { type: string, enum: [raw, opus], default: raw } }
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/octet-stream:
|
|
schema: { type: string, contentEncoding: binary }
|
|
responses:
|
|
"200": { description: Newline-delimited Volcengine ASR result frames }
|
|
default: { $ref: "#/components/responses/GatewayError" }
|
|
/v1/gateway/asr/sessions:
|
|
post:
|
|
summary: Reserve credits and create a one-shot streaming ASR session
|
|
parameters:
|
|
- $ref: "#/components/parameters/RequestId"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/CreateAsrSessionRequest" }
|
|
responses:
|
|
"201":
|
|
description: Session created
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/CreateAsrSessionResponse" }
|
|
default: { $ref: "#/components/responses/GatewayError" }
|
|
/v1/gateway/asr/sessions/{sessionId}/stream:
|
|
get:
|
|
summary: Upgrade to WebSocket and stream binary audio frames
|
|
description: |
|
|
Send authenticated binary audio frames, then the exact text frame
|
|
`{"type":"end"}`. The server forwards binary provider-result frames and
|
|
closes the one-shot session after settlement.
|
|
parameters:
|
|
- name: sessionId
|
|
in: path
|
|
required: true
|
|
schema: { type: string, format: uuid }
|
|
responses:
|
|
"101": { description: WebSocket upgrade }
|
|
default: { $ref: "#/components/responses/GatewayError" }
|
|
/.well-known/apple-app-site-association:
|
|
get:
|
|
servers:
|
|
- url: https://osglab.com
|
|
security: []
|
|
summary: Return the Apple Universal Links association document
|
|
responses:
|
|
"200":
|
|
description: AASA JSON without a redirect
|
|
headers:
|
|
Cache-Control:
|
|
schema: { type: string, const: "no-store, max-age=0" }
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AppleAppSiteAssociation" }
|
|
/apple-app-site-association:
|
|
get:
|
|
servers:
|
|
- url: https://osglab.com
|
|
security: []
|
|
summary: Return the root compatibility AASA document
|
|
responses:
|
|
"200":
|
|
description: AASA JSON without a redirect
|
|
headers:
|
|
Cache-Control:
|
|
schema: { type: string, const: "no-store, max-age=0" }
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AppleAppSiteAssociation" }
|
|
/i/{code}:
|
|
get:
|
|
servers:
|
|
- url: https://osglab.com
|
|
security: []
|
|
summary: Privacy-preserving invitation landing page
|
|
parameters:
|
|
- name: code
|
|
in: path
|
|
required: true
|
|
schema: { type: string, pattern: "^[A-Za-z0-9_-]{22}$" }
|
|
responses:
|
|
"200": { description: Bilingual HTML landing page }
|
|
"404": { description: Invalid, unknown, or expired invitation }
|
|
"503": { description: Invitation lookup is temporarily unavailable }
|
|
/v1/admin/auth/session:
|
|
get:
|
|
security:
|
|
- adminMtls: []
|
|
summary: Check the current administrator session
|
|
responses:
|
|
"200":
|
|
description: Authenticated or anonymous session state
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminSessionState" }
|
|
"404": { description: Verified administrator client certificate is absent }
|
|
/v1/admin/auth/login:
|
|
post:
|
|
security:
|
|
- adminMtls: []
|
|
summary: Authenticate an administrator with password and TOTP
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [username, password, totpCode]
|
|
properties:
|
|
username: { type: string, minLength: 3, maxLength: 64 }
|
|
password: { type: string, minLength: 1, maxLength: 1024 }
|
|
totpCode: { type: string, pattern: "^[0-9]{6}$" }
|
|
responses:
|
|
"200":
|
|
description: Secure session and CSRF cookies created
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminLoginResponse" }
|
|
"401": { description: Credentials are invalid }
|
|
"429": { description: Login is locked or rate limited }
|
|
/v1/admin/auth/logout:
|
|
post:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Revoke the current administrator session
|
|
parameters:
|
|
- $ref: "#/components/parameters/AdminCsrf"
|
|
responses:
|
|
"204": { description: Session revoked }
|
|
"401": { description: Session is invalid }
|
|
/v1/admin/overview:
|
|
get:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Return registration, activity, and credit overview statistics
|
|
parameters:
|
|
- $ref: "#/components/parameters/AdminRange"
|
|
responses:
|
|
"200":
|
|
description: Overview statistics
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminOverview" }
|
|
"400": { description: Range is invalid }
|
|
"401": { description: Session is invalid }
|
|
/v1/admin/referrals:
|
|
get:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Return referral funnel and ranking statistics
|
|
parameters:
|
|
- $ref: "#/components/parameters/AdminRange"
|
|
responses:
|
|
"200":
|
|
description: Referral statistics
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminReferralOverview" }
|
|
"400": { description: Range is invalid }
|
|
"401": { description: Session is invalid }
|
|
/v1/admin/users:
|
|
get:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: List users or search by full or 8-character internal user ID suffix
|
|
parameters:
|
|
- name: q
|
|
in: query
|
|
schema: { type: string, maxLength: 36 }
|
|
- name: cursor
|
|
in: query
|
|
schema: { type: string, maxLength: 256 }
|
|
- $ref: "#/components/parameters/Limit"
|
|
responses:
|
|
"200":
|
|
description: Privacy-minimized user summaries
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminUserPage" }
|
|
"400": { description: Query or cursor is malformed }
|
|
"401": { description: Session is invalid }
|
|
"403": { description: ANALYST role cannot access user records }
|
|
/v1/admin/users/{userId}:
|
|
get:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Return privacy-minimized user details
|
|
parameters:
|
|
- $ref: "#/components/parameters/AdminUserId"
|
|
responses:
|
|
"200":
|
|
description: User details
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminUserDetail" }
|
|
"403": { description: ANALYST role cannot access user records }
|
|
"404": { description: User was not found }
|
|
/v1/admin/users/{userId}/ledger:
|
|
get:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Return the immutable credit ledger for a user
|
|
parameters:
|
|
- $ref: "#/components/parameters/AdminUserId"
|
|
- name: cursor
|
|
in: query
|
|
schema: { type: string, maxLength: 256 }
|
|
- $ref: "#/components/parameters/Limit"
|
|
responses:
|
|
"200":
|
|
description: Credit ledger entries ordered by creation time and entry ID
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminLedgerPage" }
|
|
"400": { description: Cursor is malformed }
|
|
"403": { description: ANALYST role cannot access credit ledger records }
|
|
"404": { description: User was not found }
|
|
/v1/admin/credits/grants:
|
|
post:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Grant integer credits through an idempotent ledger transaction
|
|
parameters:
|
|
- $ref: "#/components/parameters/AdminCsrf"
|
|
- $ref: "#/components/parameters/IdempotencyKey"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [userId, amount, reason]
|
|
properties:
|
|
userId: { type: string, format: uuid }
|
|
amount: { type: integer, format: int64, minimum: 1 }
|
|
reason: { type: string, minLength: 4, maxLength: 200 }
|
|
responses:
|
|
"200":
|
|
description: Grant applied or replayed
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminGrantResponse" }
|
|
"400": { description: Grant input or idempotency key is invalid }
|
|
"403": { description: CSRF or role authorization failed }
|
|
"404": { description: Target user was not found }
|
|
"409": { description: Idempotency key conflicts with another grant }
|
|
/v1/admin/operators/summary:
|
|
get:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Return administrator and active-session security indicators
|
|
responses:
|
|
"200":
|
|
description: Security indicators
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [enabledOperators, lockedOperators, activeSessions]
|
|
properties:
|
|
enabledOperators: { type: integer, minimum: 0 }
|
|
lockedOperators: { type: integer, minimum: 0 }
|
|
activeSessions: { type: integer, format: int64, minimum: 0 }
|
|
"403": { description: INSUFFICIENT_PERMISSION; SUPER_ADMIN is required }
|
|
/v1/admin/operators:
|
|
get:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: List administrator operators
|
|
parameters:
|
|
- name: cursor
|
|
in: query
|
|
schema: { type: string, maxLength: 256 }
|
|
- $ref: "#/components/parameters/Limit"
|
|
responses:
|
|
"200":
|
|
description: Operators ordered by creation time
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminOperatorPage" }
|
|
"403": { description: INSUFFICIENT_PERMISSION; SUPER_ADMIN is required }
|
|
"400": { description: Cursor or limit is malformed }
|
|
post:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Create an operator and return TOTP provisioning data once
|
|
parameters:
|
|
- $ref: "#/components/parameters/AdminCsrf"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminOperatorCreateRequest" }
|
|
responses:
|
|
"201":
|
|
description: Operator created; plaintext TOTP material is returned only here
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminOperatorProvisioning" }
|
|
"400": { description: VALIDATION_ERROR }
|
|
"403": { description: CSRF_INVALID, ORIGIN_INVALID, or INSUFFICIENT_PERMISSION }
|
|
"409": { description: ADMIN_USERNAME_CONFLICT }
|
|
/v1/admin/operators/{operatorId}/enable:
|
|
post:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Enable an operator
|
|
parameters:
|
|
- $ref: "#/components/parameters/AdminOperatorId"
|
|
- $ref: "#/components/parameters/AdminCsrf"
|
|
responses:
|
|
"204": { description: Operator enabled and action audited }
|
|
"403": { description: CSRF_INVALID, ORIGIN_INVALID, or INSUFFICIENT_PERMISSION }
|
|
"404": { description: ADMIN_OPERATOR_NOT_FOUND }
|
|
/v1/admin/operators/{operatorId}/disable:
|
|
post:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Disable an operator and atomically revoke all active sessions
|
|
parameters:
|
|
- $ref: "#/components/parameters/AdminOperatorId"
|
|
- $ref: "#/components/parameters/AdminCsrf"
|
|
responses:
|
|
"204": { description: Operator disabled and sessions revoked }
|
|
"403": { description: CSRF_INVALID, ORIGIN_INVALID, or INSUFFICIENT_PERMISSION }
|
|
"404": { description: ADMIN_OPERATOR_NOT_FOUND }
|
|
"409": { description: CANNOT_DISABLE_SELF or LAST_SUPER_ADMIN_REQUIRED }
|
|
/v1/admin/operators/{operatorId}/unlock:
|
|
post:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Clear an operator login lock
|
|
parameters:
|
|
- $ref: "#/components/parameters/AdminOperatorId"
|
|
- $ref: "#/components/parameters/AdminCsrf"
|
|
responses:
|
|
"204": { description: Operator unlocked }
|
|
"403": { description: CSRF_INVALID, ORIGIN_INVALID, or INSUFFICIENT_PERMISSION }
|
|
"404": { description: ADMIN_OPERATOR_NOT_FOUND }
|
|
/v1/admin/operators/{operatorId}/credentials/reset:
|
|
post:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Reset password and TOTP, atomically revoking all active sessions
|
|
parameters:
|
|
- $ref: "#/components/parameters/AdminOperatorId"
|
|
- $ref: "#/components/parameters/AdminCsrf"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminOperatorPasswordRequest" }
|
|
responses:
|
|
"200":
|
|
description: Credentials reset; plaintext TOTP material is returned only here
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminOperatorProvisioning" }
|
|
"400": { description: VALIDATION_ERROR }
|
|
"403": { description: CSRF_INVALID, ORIGIN_INVALID, or INSUFFICIENT_PERMISSION }
|
|
"404": { description: ADMIN_OPERATOR_NOT_FOUND }
|
|
/v1/admin/operators/{operatorId}/sessions/revoke:
|
|
post:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Revoke every active session for an operator
|
|
parameters:
|
|
- $ref: "#/components/parameters/AdminOperatorId"
|
|
- $ref: "#/components/parameters/AdminCsrf"
|
|
responses:
|
|
"204": { description: All active sessions revoked }
|
|
"403": { description: CSRF_INVALID, ORIGIN_INVALID, or INSUFFICIENT_PERMISSION }
|
|
"404": { description: ADMIN_OPERATOR_NOT_FOUND }
|
|
/v1/admin/audit:
|
|
get:
|
|
security:
|
|
- adminMtls: []
|
|
adminSession: []
|
|
summary: Return append-only administrator audit events
|
|
parameters:
|
|
- name: cursor
|
|
in: query
|
|
schema: { type: string, maxLength: 256 }
|
|
- $ref: "#/components/parameters/Limit"
|
|
responses:
|
|
"200":
|
|
description: Recent audit events
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/AdminAuditPage" }
|
|
"400": { description: Cursor is malformed }
|
|
"403": { description: Super-administrator role is required }
|
|
components:
|
|
securitySchemes:
|
|
bearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
adminMtls:
|
|
type: mutualTLS
|
|
description: Client certificate issued by the dedicated administrator CA.
|
|
adminSession:
|
|
type: apiKey
|
|
in: cookie
|
|
name: osg_admin_session
|
|
parameters:
|
|
Limit:
|
|
name: limit
|
|
in: query
|
|
schema: { type: integer, minimum: 1, maximum: 100, default: 50 }
|
|
RequestId:
|
|
name: X-Request-ID
|
|
in: header
|
|
required: true
|
|
schema: { type: string, pattern: "^[A-Za-z0-9_-]{8,64}$" }
|
|
IdempotencyKey:
|
|
name: Idempotency-Key
|
|
in: header
|
|
required: true
|
|
schema: { type: string, minLength: 8, maxLength: 128 }
|
|
AdminCsrf:
|
|
name: X-CSRF-Token
|
|
in: header
|
|
required: true
|
|
schema: { type: string, minLength: 32, maxLength: 512 }
|
|
AdminRange:
|
|
name: range
|
|
in: query
|
|
schema: { type: string, enum: [7d, 30d, 90d], default: 30d }
|
|
AdminUserId:
|
|
name: userId
|
|
in: path
|
|
required: true
|
|
schema: { type: string, format: uuid }
|
|
AdminOperatorId:
|
|
name: operatorId
|
|
in: path
|
|
required: true
|
|
schema: { type: string, format: uuid }
|
|
responses:
|
|
HealthUp:
|
|
description: Service is healthy
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [status]
|
|
properties:
|
|
status: { type: string, const: UP }
|
|
Error:
|
|
description: API error
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/ApiErrorEnvelope" }
|
|
GatewayError:
|
|
description: Managed-provider error
|
|
content:
|
|
application/json:
|
|
schema: { $ref: "#/components/schemas/GatewayError" }
|
|
schemas:
|
|
AdminSessionState:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [authenticated]
|
|
properties:
|
|
authenticated: { type: boolean }
|
|
operatorName: { type: ["string", "null"], minLength: 3, maxLength: 64 }
|
|
role:
|
|
type: ["string", "null"]
|
|
enum: [SUPER_ADMIN, SUPPORT, ANALYST, null]
|
|
description: CSRF material is intentionally not reconstructed or returned by session checks.
|
|
AdminLoginResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [operatorName, role, csrfToken]
|
|
properties:
|
|
operatorName: { type: string, minLength: 3, maxLength: 64 }
|
|
role: { type: string, enum: [SUPER_ADMIN, SUPPORT, ANALYST] }
|
|
csrfToken:
|
|
type: string
|
|
minLength: 32
|
|
maxLength: 512
|
|
description: Returned once for the new session; the CSRF cookie is the reload fallback.
|
|
AdminUsageAggregate:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [kind, requests, chargedCredits, asrMillis, inputTokens, outputTokens]
|
|
properties:
|
|
kind: { type: string }
|
|
requests: { type: integer, format: int64, minimum: 0 }
|
|
chargedCredits: { type: integer, format: int64, minimum: 0 }
|
|
asrMillis: { type: integer, format: int64, minimum: 0 }
|
|
inputTokens: { type: integer, format: int64, minimum: 0 }
|
|
outputTokens: { type: integer, format: int64, minimum: 0 }
|
|
AdminTrendPoint:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [date, registrations, creditsUsed]
|
|
properties:
|
|
date: { type: string, format: date }
|
|
registrations: { type: integer, format: int64, minimum: 0 }
|
|
creditsUsed: { type: integer, format: int64, minimum: 0 }
|
|
AdminOverview:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- totalUsers
|
|
- activeUsers
|
|
- newUsers
|
|
- totalCreditBalance
|
|
- creditsGranted
|
|
- creditsUsed
|
|
- trend
|
|
- usage
|
|
properties:
|
|
totalUsers: { type: integer, format: int64, minimum: 0 }
|
|
activeUsers: { type: integer, format: int64, minimum: 0 }
|
|
newUsers: { type: integer, format: int64, minimum: 0 }
|
|
totalCreditBalance: { type: integer, format: int64, minimum: 0 }
|
|
creditsGranted: { type: integer, format: int64, minimum: 0 }
|
|
creditsUsed: { type: integer, format: int64, minimum: 0 }
|
|
trend:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/AdminTrendPoint" }
|
|
usage:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/AdminUsageAggregate" }
|
|
AdminFunnelStep:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [label, count]
|
|
properties:
|
|
label:
|
|
type: string
|
|
enum: [邀请码创建, 成功绑定, 有效使用并奖励, 待资格确认, 不符合奖励条件]
|
|
count: { type: integer, format: int64, minimum: 0 }
|
|
AdminReferralRank:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [userId, invited, qualified, creditsEarned]
|
|
properties:
|
|
userId: { type: string, format: uuid }
|
|
invited: { type: integer, format: int64, minimum: 0 }
|
|
qualified: { type: integer, format: int64, minimum: 0 }
|
|
creditsEarned: { type: integer, format: int64, minimum: 0 }
|
|
AdminReferralOverview:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [pendingBindings, ineligibleBindings, funnel, ranking]
|
|
properties:
|
|
pendingBindings: { type: integer, format: int64, minimum: 0 }
|
|
ineligibleBindings: { type: integer, format: int64, minimum: 0 }
|
|
funnel:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/AdminFunnelStep" }
|
|
ranking:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/AdminReferralRank" }
|
|
AdminUserSummary:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [userId, displayName, status, creditBalance, consumedCredits, createdAt]
|
|
properties:
|
|
userId: { type: string, format: uuid }
|
|
displayName: { type: string }
|
|
status: { type: string, enum: [active, suspended, closed] }
|
|
creditBalance: { type: integer, format: int64, minimum: 0 }
|
|
consumedCredits: { type: integer, format: int64, minimum: 0 }
|
|
createdAt: { type: string, format: date-time }
|
|
AdminUserPage:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/AdminUserSummary" }
|
|
nextCursor: { type: ["string", "null"] }
|
|
AdminUserReferral:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [invitedUsers, rewardedInvites]
|
|
properties:
|
|
inviterUserId: { type: ["string", "null"], format: uuid }
|
|
invitedUsers: { type: integer, format: int64, minimum: 0 }
|
|
rewardedInvites: { type: integer, format: int64, minimum: 0 }
|
|
AdminUserDetail:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- userId
|
|
- displayName
|
|
- status
|
|
- creditBalance
|
|
- consumedCredits
|
|
- createdAt
|
|
- qualifiedUsage
|
|
- usage
|
|
- referral
|
|
properties:
|
|
userId: { type: string, format: uuid }
|
|
displayName: { type: string }
|
|
status: { type: string, enum: [active, suspended, closed] }
|
|
creditBalance: { type: integer, format: int64, minimum: 0 }
|
|
consumedCredits: { type: integer, format: int64, minimum: 0 }
|
|
createdAt: { type: string, format: date-time }
|
|
lastActiveAt: { type: ["string", "null"], format: date-time }
|
|
qualifiedUsage: { type: boolean }
|
|
referralCode: { type: ["string", "null"] }
|
|
referredByUserId: { type: ["string", "null"], format: uuid }
|
|
usage:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/AdminUsageAggregate" }
|
|
referral: { $ref: "#/components/schemas/AdminUserReferral" }
|
|
AdminLedgerEntry:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [entryId, type, amount, balanceAfter, reasonCode, createdAt]
|
|
properties:
|
|
entryId: { type: string, format: uuid }
|
|
type: { type: string, enum: [grant, reserve, settle, refund, adjustment] }
|
|
amount: { type: integer, format: int64 }
|
|
balanceAfter: { type: integer, format: int64, minimum: 0 }
|
|
reasonCode: { type: string }
|
|
createdAt: { type: string, format: date-time }
|
|
AdminLedgerPage:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/AdminLedgerEntry" }
|
|
nextCursor: { type: ["string", "null"] }
|
|
AdminGrantResponse:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [transactionId, balanceAfter]
|
|
properties:
|
|
transactionId: { type: string, format: uuid }
|
|
balanceAfter: { type: integer, format: int64, minimum: 0 }
|
|
AdminAudit:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [auditId, operatorName, action, targetType, targetId, result, createdAt]
|
|
properties:
|
|
auditId: { type: string, format: uuid }
|
|
operatorName: { type: string }
|
|
action: { type: string }
|
|
targetType: { type: string }
|
|
targetId: { type: string }
|
|
requestId: { type: ["string", "null"] }
|
|
result: { type: string, enum: [success, rejected] }
|
|
createdAt: { type: string, format: date-time }
|
|
AdminAuditPage:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/AdminAudit" }
|
|
nextCursor: { type: ["string", "null"] }
|
|
AdminOperator:
|
|
type: object
|
|
additionalProperties: false
|
|
required:
|
|
- operatorId
|
|
- username
|
|
- role
|
|
- enabled
|
|
- failedLoginCount
|
|
- createdAt
|
|
- updatedAt
|
|
properties:
|
|
operatorId: { type: string, format: uuid }
|
|
username:
|
|
type: string
|
|
pattern: "^[a-z0-9][a-z0-9._@-]{2,63}$"
|
|
role: { type: string, enum: [SUPER_ADMIN, SUPPORT, ANALYST] }
|
|
enabled: { type: boolean }
|
|
failedLoginCount: { type: integer, minimum: 0 }
|
|
lockedUntil: { type: ["string", "null"], format: date-time }
|
|
lastLoginAt: { type: ["string", "null"], format: date-time }
|
|
createdAt: { type: string, format: date-time }
|
|
updatedAt: { type: string, format: date-time }
|
|
AdminOperatorPage:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [items]
|
|
properties:
|
|
items:
|
|
type: array
|
|
items: { $ref: "#/components/schemas/AdminOperator" }
|
|
nextCursor: { type: ["string", "null"] }
|
|
AdminOperatorCreateRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [username, password, role]
|
|
properties:
|
|
username:
|
|
type: string
|
|
minLength: 3
|
|
maxLength: 64
|
|
pattern: "^[A-Za-z0-9][A-Za-z0-9._@-]{2,63}$"
|
|
password: { type: string, minLength: 12, maxLength: 1024 }
|
|
role: { type: string, enum: [SUPER_ADMIN, SUPPORT, ANALYST] }
|
|
AdminOperatorPasswordRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [password]
|
|
properties:
|
|
password: { type: string, minLength: 12, maxLength: 1024 }
|
|
AdminOperatorProvisioning:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [operatorId, totpSecret, otpauthUri]
|
|
properties:
|
|
operatorId: { type: string, format: uuid }
|
|
operator:
|
|
oneOf:
|
|
- $ref: "#/components/schemas/AdminOperator"
|
|
- type: "null"
|
|
totpSecret:
|
|
type: string
|
|
pattern: "^[A-Z2-7]{32}$"
|
|
description: 160-bit Base32 secret returned once; never persisted in plaintext.
|
|
otpauthUri:
|
|
type: string
|
|
pattern: "^otpauth://totp/"
|
|
description: Provisioning URI returned once; never persisted.
|
|
AppleSignInRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [identityToken, authorizationCode, nonce]
|
|
properties:
|
|
identityToken:
|
|
type: string
|
|
description: Identity token returned by Sign in with Apple.
|
|
authorizationCode:
|
|
type: string
|
|
description: Single-use authorization code returned by Sign in with Apple.
|
|
nonce:
|
|
type: string
|
|
description: Raw nonce whose lowercase SHA-256 hex digest was sent to Apple.
|
|
displayName:
|
|
type: ["string", "null"]
|
|
maxLength: 128
|
|
description: Optional first-authorization Apple name used only to seed the nickname.
|
|
deviceCheckToken:
|
|
type: ["string", "null"]
|
|
description: Ephemeral DeviceCheck token; never persisted in plaintext.
|
|
appAttest:
|
|
oneOf:
|
|
- $ref: "#/components/schemas/AppAttestAssertion"
|
|
- type: "null"
|
|
AppAttestAssertion:
|
|
type: object
|
|
description: |
|
|
For Apple sign-in, generate the assertion with `clientDataHash` equal to
|
|
SHA-256 of the exact UTF-8 payload below, including the final line feed:
|
|
|
|
```
|
|
osg-app-attest-v1
|
|
purpose=apple-sign-in
|
|
challenge=<challenge>
|
|
identity_token_sha256=<identity-token-digest>
|
|
authorization_code_sha256=<authorization-code-digest>
|
|
nonce_sha256=<raw-nonce-digest>
|
|
```
|
|
|
|
`challenge` is the Base64URL value returned by `/v1/integrity/challenges`.
|
|
Each digest is SHA-256 of the corresponding UTF-8 request value, encoded
|
|
as unpadded Base64URL. The server reconstructs this payload and never
|
|
trusts a client-supplied hash.
|
|
additionalProperties: false
|
|
required: [keyId, challengeId, challenge, assertion]
|
|
properties:
|
|
keyId: { type: string, maxLength: 128 }
|
|
challengeId: { type: string, format: uuid }
|
|
challenge: { type: string, description: Base64URL challenge returned by the server }
|
|
assertion: { type: string, contentEncoding: base64 }
|
|
SessionTokenResponse:
|
|
type: object
|
|
required: [accountId, tokenType, accessToken, accessTokenExpiresAtEpochSeconds, refreshToken, refreshTokenExpiresAtEpochSeconds]
|
|
properties:
|
|
accountId: { type: string, format: uuid }
|
|
tokenType: { type: string, const: Bearer }
|
|
accessToken: { type: string }
|
|
accessTokenExpiresAtEpochSeconds: { type: integer, format: int64 }
|
|
refreshToken: { type: string }
|
|
refreshTokenExpiresAtEpochSeconds: { type: integer, format: int64 }
|
|
SessionTokenEnvelope:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [data]
|
|
properties:
|
|
data: { $ref: "#/components/schemas/SessionTokenResponse" }
|
|
Account:
|
|
type: object
|
|
required: [id, createdAtEpochSeconds]
|
|
properties:
|
|
id: { type: string, format: uuid }
|
|
createdAtEpochSeconds: { type: integer, format: int64 }
|
|
displayName:
|
|
type: ["string", "null"]
|
|
maxLength: 64
|
|
AccountEnvelope:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [data]
|
|
properties:
|
|
data: { $ref: "#/components/schemas/Account" }
|
|
UpdateAccountProfileRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [displayName]
|
|
properties:
|
|
displayName:
|
|
type: string
|
|
minLength: 1
|
|
maxLength: 64
|
|
DeleteAccountRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [identityToken, authorizationCode, nonce]
|
|
properties:
|
|
identityToken: { type: string, maxLength: 16384 }
|
|
authorizationCode: { type: string, maxLength: 4096 }
|
|
nonce: { type: string, maxLength: 512 }
|
|
CreditAccount:
|
|
type: object
|
|
additionalProperties: true
|
|
required: [userId, balance, lifetimeUsed]
|
|
properties:
|
|
userId: { type: string, format: uuid }
|
|
balance: { type: integer, format: int64, minimum: 0 }
|
|
lifetimeUsed:
|
|
type: integer
|
|
format: int64
|
|
minimum: 0
|
|
description: Settled usage minus credits returned by refunds
|
|
LedgerEntry:
|
|
type: object
|
|
additionalProperties: true
|
|
required: [id, amountDelta, balanceAfter]
|
|
properties:
|
|
id: { type: string, format: uuid }
|
|
amountDelta: { type: integer, format: int64 }
|
|
balanceAfter: { type: integer, format: int64, minimum: 0 }
|
|
StoreKitProduct:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [productId, credits]
|
|
properties:
|
|
productId:
|
|
type: string
|
|
enum: [500tks, 1500tks, 3000tks]
|
|
credits: { type: integer, format: int64, minimum: 1 }
|
|
StoreKitTransactionRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [signedTransaction]
|
|
properties:
|
|
signedTransaction:
|
|
type: string
|
|
minLength: 100
|
|
maxLength: 32768
|
|
description: StoreKit 2 VerificationResult.jwsRepresentation
|
|
StoreKitPurchase:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [transactionId, productId, creditsGranted, balanceAfter, replayed]
|
|
properties:
|
|
transactionId: { type: string, pattern: "^[0-9]{1,64}$" }
|
|
productId: { type: string, minLength: 3, maxLength: 128 }
|
|
creditsGranted: { type: integer, format: int64, minimum: 1 }
|
|
balanceAfter: { type: integer, format: int64, minimum: 0 }
|
|
replayed: { type: boolean }
|
|
AppleAppSiteAssociation:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [applinks]
|
|
properties:
|
|
applinks:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [details]
|
|
properties:
|
|
details:
|
|
type: array
|
|
items:
|
|
type: object
|
|
required: [appIDs, components]
|
|
properties:
|
|
appIDs:
|
|
type: array
|
|
items: { type: string }
|
|
components:
|
|
type: array
|
|
items: { type: object, additionalProperties: true }
|
|
ReferralCode:
|
|
type: object
|
|
additionalProperties: true
|
|
properties:
|
|
code: { type: string, pattern: "^[A-Za-z0-9_-]{22}$" }
|
|
RedeemReferralRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [code]
|
|
properties:
|
|
code: { type: string, pattern: "^[A-Za-z0-9_-]{22}$" }
|
|
AppAttestChallengeRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [purpose, keyId]
|
|
properties:
|
|
purpose: { type: string, enum: [attestation, assertion] }
|
|
keyId: { type: string, maxLength: 128 }
|
|
AppAttestChallengeResponse:
|
|
type: object
|
|
required: [challengeId, challenge, expiresAtEpochSeconds]
|
|
properties:
|
|
challengeId: { type: string, format: uuid }
|
|
challenge: { type: string }
|
|
expiresAtEpochSeconds: { type: integer, format: int64 }
|
|
AppAttestationRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [challengeId, challenge, keyId, attestationObject]
|
|
properties:
|
|
challengeId: { type: string, format: uuid }
|
|
challenge: { type: string }
|
|
keyId: { type: string }
|
|
attestationObject: { type: string, contentEncoding: base64 }
|
|
AppAssertionRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [challengeId, challenge, keyId, assertion, clientDataHash]
|
|
properties:
|
|
challengeId: { type: string, format: uuid }
|
|
challenge: { type: string }
|
|
keyId: { type: string }
|
|
assertion: { type: string, contentEncoding: base64 }
|
|
clientDataHash: { type: string, description: Base64URL SHA-256 of the echoed challenge }
|
|
TextGatewayRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [input]
|
|
properties:
|
|
input: { type: string, minLength: 1, maxLength: 32000 }
|
|
context: { type: ["string", "null"], maxLength: 32000 }
|
|
maxOutputTokens: { type: integer, minimum: 1, maximum: 4096, default: 512 }
|
|
temperature: { type: number, minimum: 0, maximum: 1, default: 0.2 }
|
|
stream: { type: boolean, default: false }
|
|
CreateGatewayGrantRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [scopes]
|
|
properties:
|
|
scopes:
|
|
type: array
|
|
uniqueItems: true
|
|
minItems: 1
|
|
items: { type: string, enum: [polish, ai, agent, asr] }
|
|
lifetimeSeconds: { type: ["integer", "null"], format: int64, minimum: 1 }
|
|
RefreshGatewayGrantRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [refreshToken]
|
|
properties:
|
|
refreshToken: { type: string, minLength: 32 }
|
|
GatewayGrantTokens:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [grantId, scopes, accessToken, accessExpiresAt, refreshToken, refreshExpiresAt]
|
|
properties:
|
|
grantId: { type: string, format: uuid }
|
|
scopes:
|
|
type: array
|
|
uniqueItems: true
|
|
items: { type: string, enum: [polish, ai, agent, asr] }
|
|
accessToken: { type: string }
|
|
accessExpiresAt: { type: string, format: date-time }
|
|
refreshToken: { type: string }
|
|
refreshExpiresAt: { type: string, format: date-time }
|
|
CreateAsrSessionRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [estimatedDurationMillis]
|
|
properties:
|
|
format: { type: string, enum: [pcm, wav, ogg, mp3], default: pcm }
|
|
codec: { type: string, enum: [raw, opus], default: raw }
|
|
sampleRate: { type: integer, const: 16000 }
|
|
bits: { type: integer, const: 16 }
|
|
channels: { type: integer, minimum: 1, maximum: 2, default: 1 }
|
|
language: { type: ["string", "null"], maxLength: 32 }
|
|
estimatedDurationMillis: { type: integer, minimum: 1, maximum: 600000 }
|
|
CreateAsrSessionResponse:
|
|
type: object
|
|
required: [sessionId, websocketPath, maxFrameBytes, idleTimeoutMillis]
|
|
properties:
|
|
sessionId: { type: string, format: uuid }
|
|
websocketPath: { type: string }
|
|
maxFrameBytes: { type: integer }
|
|
idleTimeoutMillis: { type: integer, format: int64 }
|
|
ApiError:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [code, message]
|
|
properties:
|
|
code: { type: string }
|
|
message: { type: string }
|
|
ApiErrorEnvelope:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [error]
|
|
properties:
|
|
error: { $ref: "#/components/schemas/ApiError" }
|
|
GatewayError:
|
|
type: object
|
|
required: [code, message, requestId]
|
|
properties:
|
|
code: { type: string }
|
|
message: { type: string }
|
|
requestId: { type: string }
|