{"openapi":"3.1.0","info":{"title":"Seams API","version":"0.0.0","description":"The Seams control plane. Paths appear here as the work that implements them lands."},"components":{"schemas":{"OpenApiDocument":{"type":"object","properties":{"openapi":{"type":"string"},"info":{"type":"object","properties":{"title":{"type":"string"},"version":{"type":"string"}},"required":["title","version"],"additionalProperties":{}}},"required":["openapi","info"],"additionalProperties":{}},"Health":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]}},"required":["status"]},"Tenant":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"displayName":{"type":"string"},"branding":{"type":"object","properties":{"productName":{"type":"string"},"primaryColor":{"type":"string"}},"required":["productName","primaryColor"]}},"required":["id","slug","displayName","branding"]},"EndUser":{"type":"object","properties":{"id":{"type":"string"},"externalId":{"type":"string"},"email":{"type":["string","null"],"description":"Null until the tenant tells us one."},"wallet":{"type":"object","properties":{"balanceMicros":{"type":"string","description":"Integer micro-dollars as a string. 1_000_000 micros = $1.00."},"reservedMicros":{"type":"string","description":"Integer micro-dollars as a string. 1_000_000 micros = $1.00."}},"required":["balanceMicros","reservedMicros"]},"usage":{"type":"object","properties":{"calls":{"type":"integer"},"inputTokens":{"type":"integer"},"outputTokens":{"type":"integer"},"billedMicros":{"type":"string","description":"Integer micro-dollars as a string. 1_000_000 micros = $1.00."}},"required":["calls","inputTokens","outputTokens","billedMicros"]}},"required":["id","externalId","email","wallet","usage"]},"Usage":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"requestedModel":{"type":"string"},"calls":{"type":"integer"},"inputTokens":{"type":"integer"},"outputTokens":{"type":"integer"},"billedMicros":{"type":"string","description":"Integer micro-dollars as a string. 1_000_000 micros = $1.00."}},"required":["requestedModel","calls","inputTokens","outputTokens","billedMicros"]}},"totals":{"type":"object","properties":{"calls":{"type":"integer"},"inputTokens":{"type":"integer"},"outputTokens":{"type":"integer"},"billedMicros":{"type":"string","description":"Integer micro-dollars as a string. 1_000_000 micros = $1.00."}},"required":["calls","inputTokens","outputTokens","billedMicros"]}},"required":["rows","totals"]},"Subscription":{"type":"object","properties":{"planName":{"type":"string"},"priceMicros":{"type":"string","description":"Integer micro-dollars as a string. 1_000_000 micros = $1.00."},"interval":{"type":"string","enum":["month","year"]},"periodStart":{"type":"string"},"periodEnd":{"type":"string"},"onDemandEnabled":{"type":"boolean"},"onDemandLimitMicros":{"type":["string","null"],"description":"The end user's own ceiling. Null while enabled means no ceiling."},"onDemandSpentMicros":{"type":"string","description":"Integer micro-dollars as a string. 1_000_000 micros = $1.00."},"pools":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"displayName":{"type":"string"},"unit":{"type":"string","enum":["tokens","micros"]},"granted":{"type":"string","description":"An integer amount as a string, in the pool's `unit`: tokens, or micro-dollars."},"consumed":{"type":"string","description":"An integer amount as a string, in the pool's `unit`: tokens, or micro-dollars."},"spilloverTo":{"type":["string","null"],"description":"The pool this one overflows into, by slug. Null when it overflows into nothing."},"thenOnDemand":{"type":"boolean","description":"Whether usage past this pool may be billed on demand, or simply stops."},"aliases":{"type":"array","items":{"type":"object","properties":{"requestedModel":{"type":"string"},"consumed":{"type":"string","description":"An integer amount as a string, in the pool's `unit`: tokens, or micro-dollars."}},"required":["requestedModel","consumed"]}}},"required":["slug","displayName","unit","granted","consumed","spilloverTo","thenOnDemand","aliases"]}},"invoices":{"type":"array","items":{"type":"object","properties":{"issuedAt":{"type":"string"},"amountMicros":{"type":"string","description":"Integer micro-dollars as a string. 1_000_000 micros = $1.00."},"status":{"type":"string","enum":["paid","open","past_due"]}},"required":["issuedAt","amountMicros","status"]}}},"required":["planName","priceMicros","interval","periodStart","periodEnd","onDemandEnabled","onDemandLimitMicros","onDemandSpentMicros","pools","invoices"]},"MintedKey":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string","description":"The secret, shown once. It is not recoverable from the row."},"keyPrefix":{"type":"string","description":"`ak_<code>_test_<six>` — the leader, not secret."},"lastFour":{"type":"string"},"endUserId":{"type":"string","description":"Our id for the person the key is bound to."},"livemode":{"type":"boolean","enum":[false]}},"required":["id","key","keyPrefix","lastFour","endUserId","livemode"]},"MintKeyRequest":{"type":"object","properties":{"endUserId":{"type":"string","minLength":1,"description":"The tenant's own identifier for the person this key spends as."},"email":{"type":"string","description":"Recorded on the end user if we do not have one."},"name":{"type":"string","description":"What to call the key in a console. Defaults to endUserId."},"livemode":{"type":"boolean","description":"Test mode only while the tenant is a header (#8). `true` is refused."}},"required":["endUserId"]},"ApiKeyList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeySummary"}}},"required":["data"]},"ApiKeySummary":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"keyPrefix":{"type":"string","description":"The leader, not secret. What a console shows in place of a key."},"lastFour":{"type":"string"},"livemode":{"type":"boolean"},"endUserId":{"type":["string","null"],"description":"The tenant's own identifier for the person the key spends as."},"actorType":{"type":"string"},"actorLabel":{"type":["string","null"]},"createdAt":{"type":"string"},"lastUsedAt":{"type":["string","null"],"description":"Null until the key is used on the gateway."},"revokedAt":{"type":["string","null"]},"expiresAt":{"type":["string","null"]}},"required":["id","name","keyPrefix","lastFour","livemode","endUserId","actorType","actorLabel","createdAt","lastUsedAt","revokedAt","expiresAt"]},"Capabilities":{"type":"object","properties":{"tier":{"type":"string","enum":["demo"]},"liveMode":{"type":"object","properties":{"enabled":{"type":"boolean","enum":[false]},"blockedBy":{"type":"string","enum":["demo_fixtures"]}},"required":["enabled","blockedBy"]},"features":{"type":"object","additionalProperties":{"type":"object","properties":{"available":{"type":"boolean"},"reason":{"type":"string","enum":["not_yet_released"]},"issue":{"type":"string","description":"The issue that will build it, when it is not built."},"pages":{"type":"array","items":{"type":"string"},"description":"Surface paths that belong to this feature when it is not built yet."}},"required":["available"]}}},"required":["tier","liveMode","features"]}},"parameters":{}},"paths":{"/v1/openapi.json":{"get":{"summary":"This document","description":"The OpenAPI 3.1 description of every path this API serves.","responses":{"200":{"description":"The OpenAPI document.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenApiDocument"}}}}}}},"/health":{"get":{"summary":"Liveness","description":"200 while this process is serving. Says nothing about the datastores behind it.","responses":{"200":{"description":"The process is serving.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}}}}},"/favicon.ico":{"get":{"summary":"The tab icon","description":"The Seams mark, for a browser that opens an api url directly.","responses":{"200":{"description":"The mark, as svg.","content":{"image/svg+xml":{"schema":{"type":"string"}}}}}}},"/v1/tenant":{"get":{"summary":"The tenant in view","description":"Identity and branding for the tenant this request reads as.","parameters":[{"schema":{"type":"string","description":"Which tenant to read as. Stands in for the credential until auth lands (#8)."},"required":true,"description":"Which tenant to read as. Stands in for the credential until auth lands (#8).","name":"x-demo-tenant","in":"header"}],"responses":{"200":{"description":"The tenant.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tenant"}}}}}}},"/v1/end-users":{"get":{"summary":"The tenant's end users","description":"Each end user with their wallet and what they have spent.","parameters":[{"schema":{"type":"string","description":"Which tenant to read as. Stands in for the credential until auth lands (#8)."},"required":true,"description":"Which tenant to read as. Stands in for the credential until auth lands (#8).","name":"x-demo-tenant","in":"header"}],"responses":{"200":{"description":"The end users of the tenant in view.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EndUser"}}},"required":["data"]}}}}}}},"/v1/usage":{"get":{"summary":"Usage by model alias","description":"Per-alias calls, tokens and spend. Scoped to one end user when `endUserId` is given.","parameters":[{"schema":{"type":"string","description":"The tenant's own identifier for an end user. Omit for the whole tenant."},"required":false,"description":"The tenant's own identifier for an end user. Omit for the whole tenant.","name":"endUserId","in":"query"},{"schema":{"type":"string","description":"Which tenant to read as. Stands in for the credential until auth lands (#8)."},"required":true,"description":"Which tenant to read as. Stands in for the credential until auth lands (#8).","name":"x-demo-tenant","in":"header"}],"responses":{"200":{"description":"Usage for the tenant, or for one of its end users.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}}}}}},"/v1/subscription":{"get":{"summary":"An end user's plan","description":"The plan, its quota pools with what each alias drew from them, and the invoices.","parameters":[{"schema":{"type":"string","description":"The tenant's own identifier for an end user. A subscription is always one person's."},"required":true,"description":"The tenant's own identifier for an end user. A subscription is always one person's.","name":"endUserId","in":"query"},{"schema":{"type":"string","description":"Which tenant to read as. Stands in for the credential until auth lands (#8)."},"required":true,"description":"Which tenant to read as. Stands in for the credential until auth lands (#8).","name":"x-demo-tenant","in":"header"}],"responses":{"200":{"description":"The subscription of the end user named by `endUserId`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Subscription"}}}}}}},"/v1/end-users/{externalId}/wallet/grant":{"post":{"summary":"Grant credit to an end user","description":"Issues credit without a payment — trials, support, seeding.","responses":{"501":{"description":"Documented, not built. The body names the issue that will build it.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["not_implemented"]},"issue":{"type":"string"}},"required":["code","issue"]}},"required":["error"]}}}}}}},"/v1/subscription/on-demand":{"post":{"summary":"Set on-demand overage","description":"Turns on-demand spending on or off, and sets the end user's own monthly ceiling.","responses":{"501":{"description":"Documented, not built. The body names the issue that will build it.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["not_implemented"]},"issue":{"type":"string"}},"required":["code","issue"]}},"required":["error"]}}}}}}},"/v1/billing/payment-portal":{"post":{"summary":"Open the payment portal","description":"A one-time link to Stripe's customer portal: card on file, invoices, receipts.","responses":{"501":{"description":"Documented, not built. The body names the issue that will build it.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["not_implemented"]},"issue":{"type":"string"}},"required":["code","issue"]}},"required":["error"]}}}}}}},"/v1/keys":{"post":{"summary":"Mint an API key","description":"Mints a key bound to one end user and their wallet, under the tenant's default bundle. The secret is in the response and nowhere else. Test mode only until #74.","parameters":[{"schema":{"type":"string","description":"Which tenant to read as. Stands in for the credential until auth lands (#8)."},"required":true,"description":"Which tenant to read as. Stands in for the credential until auth lands (#8).","name":"x-demo-tenant","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintKeyRequest"}}}},"responses":{"200":{"description":"The minted key. Store the secret now; it cannot be read back.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintedKey"}}}}}},"get":{"summary":"Every key this tenant has minted","description":"Prefix, last four and who each key spends as. The secret is not here and cannot be — only its hash was stored. Revoked keys are listed, because the revocation is the evidence.","parameters":[{"schema":{"type":"string","description":"Which tenant to read as. Stands in for the credential until auth lands (#8)."},"required":true,"description":"Which tenant to read as. Stands in for the credential until auth lands (#8).","name":"x-demo-tenant","in":"header"}],"responses":{"200":{"description":"The tenant's keys, newest first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyList"}}}}}}},"/v1/chat/completions":{"post":{"summary":"Run an inference request","description":"The OpenAI-shaped inference path, metered against the caller's wallet. Served by the gateway, not by this host — send it to the gateway's base url.","responses":{"501":{"description":"Documented, not built. The body names the issue that will build it.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["not_implemented"]},"issue":{"type":"string"}},"required":["code","issue"]}},"required":["error"]}}}}}}},"/v1/capabilities":{"get":{"summary":"What is available to this tenant","description":"Every feature, available or not, with the reason and the issue when it is not.","parameters":[{"schema":{"type":"string","description":"Which tenant to read as. Stands in for the credential until auth lands (#8)."},"required":true,"description":"Which tenant to read as. Stands in for the credential until auth lands (#8).","name":"x-demo-tenant","in":"header"}],"responses":{"200":{"description":"The capability map.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Capabilities"}}}}}}}},"webhooks":{}}