Establish secure account and managed AI backend
Provide the production foundation for Apple identity, immutable credits, referrals, integrity checks, managed providers, and hardened Docker deployment.
This commit is contained in:
@@ -0,0 +1,678 @@
|
||||
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 minimal account profile
|
||||
responses:
|
||||
"200":
|
||||
description: 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 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/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 current referral code and binding
|
||||
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 }
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
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: 1, maxLength: 255 }
|
||||
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:
|
||||
AppleSignInRequest:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [identityToken, authorizationCode, nonce]
|
||||
properties:
|
||||
identityToken: { type: string }
|
||||
authorizationCode: { type: string }
|
||||
nonce: { type: string }
|
||||
deviceCheckToken:
|
||||
type: ["string", "null"]
|
||||
description: Ephemeral DeviceCheck token; never persisted in plaintext.
|
||||
appAttest:
|
||||
oneOf:
|
||||
- $ref: "#/components/schemas/AppAttestAssertion"
|
||||
- type: "null"
|
||||
AppAttestAssertion:
|
||||
type: object
|
||||
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 }
|
||||
AccountEnvelope:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [data]
|
||||
properties:
|
||||
data: { $ref: "#/components/schemas/Account" }
|
||||
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]
|
||||
properties:
|
||||
userId: { type: string, format: uuid }
|
||||
balance: { type: integer, format: int64, minimum: 0 }
|
||||
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 }
|
||||
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 }
|
||||
Reference in New Issue
Block a user