{"openapi":"3.1.0","info":{"title":"Ternis Auth & SSO API","version":"1.0.0","description":"Multi-domain OAuth 2.0 and OpenID Connect (OIDC) Single Sign-On (SSO) platform powering the Ternis ecosystem (ternis.net, ternis.org, ternis.dev, auth.t-api.de, auth.thosted.de). Provides unified identity, role-based authorization, and user classification for Ternis Members, General Users, Paying Customers, and Partners.","contact":{"name":"Ternis Platform Engineering","url":"https:\/\/ternis.dev","email":"auth-support@ternis.net"},"license":{"name":"MIT","url":"https:\/\/opensource.org\/licenses\/MIT"}},"servers":[{"url":"https:\/\/auth.ternis.dev","description":"Current active host (auth.ternis.dev)"},{"url":"https:\/\/auth.ternis.net","description":"Primary Production Auth Network (.net)"},{"url":"https:\/\/auth.ternis.org","description":"Ternis Foundation Auth (.org)"},{"url":"https:\/\/auth.ternis.dev","description":"Ternis Developer Sandbox (.dev)"},{"url":"https:\/\/auth.t-api.de","description":"t-API Authentication Gateway (.de)"},{"url":"https:\/\/auth.thosted.de","description":"tHosted Single Sign-On Gateway (.de)"},{"url":"https:\/\/user.t-api.de","description":"t-API User Profile & Avatar CDN (.de)"},{"url":"https:\/\/user.t-cdn.de","description":"t-CDN User Profile & Avatar Edge (.de)"},{"url":"https:\/\/avatar.t-cdn.de","description":"t-CDN Avatar Edge Network (.de)"}],"tags":[{"name":"OAuth2 \/ OpenID Connect","description":"Standard RFC 6749, RFC 7636 (PKCE), and OpenID Connect endpoints"},{"name":"User Profile & Identity","description":"Authenticated user profile, classification, avatar, and metadata"},{"name":"Organizations & Memberships","description":"Ternis team memberships and organizational affiliations"},{"name":"Partner Developer Console","description":"OAuth client registration and partner integrations"},{"name":"Plans & Entitlements","description":"Commercial subscription plans, feature flags, and limits"},{"name":"Address Book & Verification","description":"Multi-address storage and secondary email verification"},{"name":"Ecosystem Wallet & Balance","description":"Unified ledger balance shared across ternisdomains.de and services"},{"name":"Ecosystem & Domains","description":"Multi-domain context and configuration discovery"}],"paths":{"\/.well-known\/openid-configuration":{"get":{"tags":["OAuth2 \/ OpenID Connect"],"summary":"OpenID Connect Discovery Document","description":"Returns standard OIDC discovery metadata pointing to active domain endpoints.","responses":{"200":{"description":"OpenID Connect Configuration JSON","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/OpenIdConfiguration"}}}}}}},"\/oauth\/authorize":{"get":{"tags":["OAuth2 \/ OpenID Connect"],"summary":"OAuth 2.0 Authorization Endpoint","description":"Initiate authorization code flow with PKCE or prompt user for consent.","parameters":[{"name":"response_type","in":"query","required":true,"schema":{"type":"string","example":"code"}},{"name":"client_id","in":"query","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string","format":"uri"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","example":"openid profile email ternis:sso"}},{"name":"state","in":"query","required":false,"schema":{"type":"string"}},{"name":"code_challenge","in":"query","required":false,"schema":{"type":"string"}},{"name":"code_challenge_method","in":"query","required":false,"schema":{"type":"string","example":"S256"}}],"responses":{"302":{"description":"Redirect to login or authorization redirect URI"},"200":{"description":"Render authorization consent dialog"}}}},"\/oauth\/token":{"post":{"tags":["OAuth2 \/ OpenID Connect"],"summary":"OAuth 2.0 Token Exchange Endpoint","description":"Exchange authorization code, client credentials, or refresh token for Bearer access token.","requestBody":{"required":true,"content":{"application\/x-www-form-urlencoded":{"schema":{"type":"object","required":["grant_type","client_id"],"properties":{"grant_type":{"type":"string","enum":["authorization_code","refresh_token","client_credentials"]},"client_id":{"type":"string","format":"uuid"},"client_secret":{"type":"string"},"redirect_uri":{"type":"string"},"code":{"type":"string"},"code_verifier":{"type":"string"},"refresh_token":{"type":"string"},"scope":{"type":"string"}}}}}},"responses":{"200":{"description":"Token exchange successful","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/TokenResponse"}}}},"401":{"description":"Invalid client credentials or code"}}}},"\/oauth\/userinfo":{"get":{"tags":["OAuth2 \/ OpenID Connect"],"summary":"OIDC UserInfo Endpoint","description":"Returns claims about the authenticated user based on granted scopes.","security":[{"OAuth2Bearer":[]}],"responses":{"200":{"description":"Standard OpenID Connect Claims","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/OidcClaims"}}}},"401":{"description":"Unauthenticated"}}}},"\/api\/v1\/user":{"get":{"tags":["User Profile & Identity"],"summary":"Get Detailed User Profile","description":"Returns comprehensive identity details including Ternis membership badges, role, partner status, and subscription tier.","security":[{"OAuth2Bearer":[]}],"responses":{"200":{"description":"User profile object","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/UserProfile"}}}}}}},"\/api\/v1\/memberships":{"get":{"tags":["Organizations & Memberships"],"summary":"List User Memberships","description":"Lists the Ternis organizations and teams that the user is a member of.","security":[{"OAuth2Bearer":[]}],"responses":{"200":{"description":"List of memberships"}}}},"\/api\/v1\/oauth\/clients":{"get":{"tags":["Partner Developer Console"],"summary":"List Registered OAuth Clients","security":[{"OAuth2Bearer":[]}],"responses":{"200":{"description":"List of developer OAuth clients"}}},"post":{"tags":["Partner Developer Console"],"summary":"Register New OAuth Client Application","security":[{"OAuth2Bearer":[]}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["name","redirect"],"properties":{"name":{"type":"string","example":"Ternis Analytics Dashboard"},"redirect":{"type":"string","example":"https:\/\/app.ternis.dev\/callback"},"confidential":{"type":"boolean","default":true},"grant_types":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"OAuth Client created"}}}},"\/api\/domains":{"get":{"tags":["Ecosystem & Domains"],"summary":"Get Ecosystem Domains & Configuration","description":"Returns active domain metadata, cluster mappings (auth.ternis.net, auth.ternis.org, auth.ternis.dev, auth.t-api.de, auth.thosted.de, user.t-api.de, user.t-cdn.de, avatar.t-cdn.de, account.ternis.org), and redirect policy.","responses":{"200":{"description":"Domain ecosystem configuration"}}}},"\/avatar\/{identifier}":{"get":{"tags":["User Profile & Identity"],"summary":"Get User Profile Picture \/ Avatar","description":"Returns user avatar image by UUID, username, or email. Supports PNG, SVG, JPG, WebP formats with automated initials and default silhouette fallback.","parameters":[{"name":"identifier","in":"path","required":true,"description":"UUID, username, or email with optional .png, .svg extension","schema":{"type":"string"}},{"name":"size","in":"query","required":false,"description":"Image dimensions in pixels (16 to 1024, default 256)","schema":{"type":"integer","default":256}},{"name":"fallback","in":"query","required":false,"description":"Fallback style: default, silhouette, initials, 404","schema":{"type":"string","default":"default"}}],"responses":{"200":{"description":"Avatar image stream","content":{"image\/png":{"schema":{"type":"string","format":"binary"}},"image\/svg+xml":{"schema":{"type":"string"}}}}}}},"\/api\/plans":{"get":{"tags":["Plans & Entitlements"],"summary":"List Available Commercial Plans","description":"Returns public list of active subscription plans, pricing, feature flags, and quotas.","responses":{"200":{"description":"List of plans","content":{"application\/json":{"schema":{"type":"array","items":{"$ref":"#\/components\/schemas\/Plan"}}}}}}}},"\/api\/v1\/plans":{"get":{"tags":["Plans & Entitlements"],"summary":"List Available Commercial Plans (v1)","security":[{"OAuth2Bearer":[]}],"responses":{"200":{"description":"List of plans","content":{"application\/json":{"schema":{"type":"array","items":{"$ref":"#\/components\/schemas\/Plan"}}}}}}}},"\/api\/v1\/user\/plan":{"get":{"tags":["Plans & Entitlements"],"summary":"Get Authenticated User Plan & Entitlements","description":"Returns the user active commercial plan, numerical quotas, and active entitlement feature keys.","security":[{"OAuth2Bearer":[]}],"responses":{"200":{"description":"User plan and entitlement flags","content":{"application\/json":{"schema":{"type":"object","properties":{"user_id":{"type":"string","format":"uuid"},"plan":{"$ref":"#\/components\/schemas\/Plan"},"features":{"type":"object"},"entitlements":{"type":"array","items":{"type":"string"}},"status":{"type":"string","example":"active"}}}}}}}}},"\/api\/v1\/user\/avatar":{"post":{"tags":["User Profile & Identity"],"summary":"Upload or Update User Profile Picture","description":"Upload an image file (PNG, JPG, WebP, SVG, GIF up to 5MB) or supply an external avatar URL.","security":[{"OAuth2Bearer":[]}],"requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"type":"object","properties":{"avatar":{"type":"string","format":"binary"},"avatar_url":{"type":"string","format":"uri"}}}},"application\/json":{"schema":{"type":"object","properties":{"avatar_url":{"type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"Avatar updated successfully"},"422":{"description":"Validation error"}}},"delete":{"tags":["User Profile & Identity"],"summary":"Remove Custom Avatar and Reset to Initials","security":[{"OAuth2Bearer":[]}],"responses":{"200":{"description":"Avatar reset to default initials\/silhouette"}}}},"\/api\/v1\/user\/addresses":{"get":{"tags":["Address Book & Verification"],"summary":"List User Addresses","description":"Returns all saved postal addresses with formatted strings and standard OIDC address claim payloads.","security":[{"OAuth2Bearer":[]}],"responses":{"200":{"description":"List of user addresses","content":{"application\/json":{"schema":{"type":"object","properties":{"addresses":{"type":"array","items":{"$ref":"#\/components\/schemas\/UserAddress"}}}}}}}}},"post":{"tags":["Address Book & Verification"],"summary":"Create New User Address","security":[{"OAuth2Bearer":[]}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["street","postal_code","city","country_code"],"properties":{"type":{"type":"string","enum":["billing","shipping","legal","office","home"]},"label":{"type":"string"},"recipient_name":{"type":"string"},"company_name":{"type":"string"},"street":{"type":"string"},"street_line_2":{"type":"string"},"postal_code":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"country_code":{"type":"string","example":"DE"},"is_primary":{"type":"boolean"},"is_billing":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Address created"},"422":{"description":"Validation error"}}}},"\/api\/v1\/user\/addresses\/{id}":{"put":{"tags":["Address Book & Verification"],"summary":"Update Address","security":[{"OAuth2Bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Address updated"},"404":{"description":"Address not found"}}},"delete":{"tags":["Address Book & Verification"],"summary":"Delete Address","security":[{"OAuth2Bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Address deleted"},"404":{"description":"Address not found"}}}},"\/api\/v1\/user\/emails":{"get":{"tags":["Address Book & Verification"],"summary":"List User Emails & Verification Status","security":[{"OAuth2Bearer":[]}],"responses":{"200":{"description":"Primary and secondary emails list","content":{"application\/json":{"schema":{"type":"object","properties":{"primary_email":{"$ref":"#\/components\/schemas\/UserEmail"},"emails":{"type":"array","items":{"$ref":"#\/components\/schemas\/UserEmail"}}}}}}}}},"post":{"tags":["Address Book & Verification"],"summary":"Add Secondary Email to Account","security":[{"OAuth2Bearer":[]}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"}}}}}},"responses":{"201":{"description":"Email added, verification token issued"},"422":{"description":"Validation error"}}}},"\/api\/v1\/user\/emails\/{id}\/verify":{"post":{"tags":["Address Book & Verification"],"summary":"Verify User Email Address","security":[{"OAuth2Bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"UUID or \"primary\"","schema":{"type":"string"}}],"responses":{"200":{"description":"Email verified"}}}},"\/api\/v1\/user\/emails\/{id}":{"delete":{"tags":["Address Book & Verification"],"summary":"Remove Secondary Email","security":[{"OAuth2Bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Email removed"}}}},"\/api\/v1\/user\/balance":{"get":{"tags":["Ecosystem Wallet & Balance"],"summary":"Get Ecosystem Wallet Balance","description":"Returns current synchronized credit balance and 10 most recent ledger transactions.","security":[{"OAuth2Bearer":[]}],"responses":{"200":{"description":"Wallet balance summary","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/BalanceSummary"}}}}}}},"\/api\/v1\/user\/balance\/charge":{"post":{"tags":["Ecosystem Wallet & Balance"],"summary":"Charge Ecosystem Balance (e.g. ternisdomains.de)","description":"Atomically deducts credits from user wallet with duplicate prevention (idempotency key) and reference ID.","security":[{"OAuth2Bearer":[]}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["amount_cents","description"],"properties":{"amount_cents":{"type":"integer","minimum":1,"example":1299},"service":{"type":"string","example":"ternisdomains.de"},"description":{"type":"string","example":"Registration of example.de (1 year)"},"reference_id":{"type":"string","example":"DOM-2026-99214"},"idempotency_key":{"type":"string","example":"tx_98a72b6c1"},"metadata":{"type":"object"}}}}}},"responses":{"200":{"description":"Balance successfully charged"},"422":{"description":"Insufficient funds or validation failure"}}}},"\/api\/v1\/user\/balance\/topup":{"post":{"tags":["Ecosystem Wallet & Balance"],"summary":"Credit \/ Top Up Ecosystem Balance","security":[{"OAuth2Bearer":[]}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["amount_cents"],"properties":{"amount_cents":{"type":"integer","minimum":100,"maximum":1000000,"example":2500},"service":{"type":"string","example":"stripe"},"description":{"type":"string","example":"Top-up \u20ac25.00 via Credit Card"},"reference_id":{"type":"string"},"idempotency_key":{"type":"string"}}}}}},"responses":{"200":{"description":"Balance credited"}}}},"\/api\/v1\/user\/balance\/transactions":{"get":{"tags":["Ecosystem Wallet & Balance"],"summary":"Get Paginated Ledger Transactions","security":[{"OAuth2Bearer":[]}],"responses":{"200":{"description":"Paginated transaction history"}}}}},"components":{"securitySchemes":{"OAuth2Bearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Access token obtained from \/oauth\/token"}},"schemas":{"OpenIdConfiguration":{"type":"object","properties":{"issuer":{"type":"string","format":"uri"},"authorization_endpoint":{"type":"string","format":"uri"},"token_endpoint":{"type":"string","format":"uri"},"userinfo_endpoint":{"type":"string","format":"uri"},"jwks_uri":{"type":"string","format":"uri"},"scopes_supported":{"type":"array","items":{"type":"string"}},"response_types_supported":{"type":"array","items":{"type":"string"}},"grant_types_supported":{"type":"array","items":{"type":"string"}}}},"TokenResponse":{"type":"object","properties":{"token_type":{"type":"string","example":"Bearer"},"expires_in":{"type":"integer","example":1296000},"access_token":{"type":"string"},"refresh_token":{"type":"string"},"scope":{"type":"string"}}},"OidcClaims":{"type":"object","properties":{"sub":{"type":"string","format":"uuid"},"name":{"type":"string"},"preferred_username":{"type":"string"},"email":{"type":"string","format":"email"},"email_verified":{"type":"boolean"},"picture":{"type":"string","format":"uri"},"user_type":{"type":"string","enum":["ternis_member","general_user","paying_customer","partner"]},"role":{"type":"string","enum":["superadmin","admin","developer","member","billing_manager","user"]},"ternis_member":{"type":"object","properties":{"is_member":{"type":"boolean"},"member_badge":{"type":"string"},"organizations":{"type":"object"}}},"ternis_customer":{"type":"object","properties":{"is_paying":{"type":"boolean"},"plan":{"type":"string"},"status":{"type":"string"}}},"ternis_partner":{"type":"object","properties":{"is_partner":{"type":"boolean"},"company_name":{"type":"string"},"tier":{"type":"string"},"verified":{"type":"boolean"}}}}},"UserProfile":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"username":{"type":"string"},"email":{"type":"string","format":"email"},"email_verified":{"type":"boolean"},"user_type":{"type":"string"},"role":{"type":"string"},"status":{"type":"string"},"avatar_url":{"type":"string","format":"uri"},"is_ternis_member":{"type":"boolean"},"is_partner":{"type":"boolean"},"is_paying_customer":{"type":"boolean"}}},"Plan":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Pro Tier"},"slug":{"type":"string","example":"pro"},"tier":{"type":"string","example":"pro"},"price_cents":{"type":"integer","example":2900},"currency":{"type":"string","example":"EUR"},"billing_interval":{"type":"string","example":"month"},"features":{"type":"object"}}},"UserAddress":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["billing","shipping","legal","office","home"]},"label":{"type":"string"},"recipient_name":{"type":"string"},"company_name":{"type":"string"},"street":{"type":"string"},"street_line_2":{"type":"string"},"postal_code":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"country_code":{"type":"string","example":"DE"},"is_primary":{"type":"boolean"},"is_billing":{"type":"boolean"},"formatted":{"type":"string"},"oidc_claim":{"type":"object"}}},"UserEmail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"is_primary":{"type":"boolean"},"is_verified":{"type":"boolean"},"verified_at":{"type":"string","format":"date-time"}}},"BalanceTransaction":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"amount_cents":{"type":"integer"},"formatted_amount":{"type":"string","example":"-\u20ac12.99"},"balance_after_cents":{"type":"integer"},"formatted_balance_after":{"type":"string","example":"\u20ac237.01"},"type":{"type":"string","enum":["credit","debit"]},"source_service":{"type":"string","example":"ternisdomains.de"},"reference_id":{"type":"string"},"description":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"BalanceSummary":{"type":"object","properties":{"user_id":{"type":"string","format":"uuid"},"balance_cents":{"type":"integer","example":25000},"formatted_balance":{"type":"string","example":"\u20ac250.00"},"currency":{"type":"string","example":"EUR"},"recent_transactions":{"type":"array","items":{"$ref":"#\/components\/schemas\/BalanceTransaction"}}}}}}}