/api/v1/* routes and POST /api/mcp require an Authorization header:
Token types
OAuth access tokens
User access tokens from the Vings OAuth flow or from a signed-in Vings session (for example, your app after the user signs in). Use the token value in theAuthorization header.
Vings personal access tokens (PAT)
Tokens prefixed withvng_pat_. Create and manage them in your Vings account settings. PATs include explicit Vings scopes and only access your data. Send the token in the Authorization header the same way as an OAuth access token.
Cookie-based auth across subdomains is not supported on this API in v1.
OAuth protected-resource metadata
MCP and REST clients that support RFC 9728 discovery can read:| URL | Resource |
|---|---|
GET /.well-known/oauth-protected-resource | MCP at /api/mcp |
GET /.well-known/oauth-protected-resource/mcp | MCP at /api/mcp |
GET /api/.well-known/oauth-protected-resource | REST API |
GET /api/.well-known/oauth-protected-resource/mcp | MCP at /api/mcp |
authorization_servers pointing at the external host (https://external.vin.gs), which publishes authorization-server discovery for sign-in, consent, and ChatGPT refresh tokens.
Authorization-server metadata (refresh tokens)
ChatGPT and other MCP clients discover refresh-token support from the authorization server, not protected-resource metadata:| URL | Purpose |
|---|---|
GET /.well-known/oauth-authorization-server | OAuth AS metadata with offline_access |
GET /.well-known/openid-configuration | OIDC discovery (same fields) |
GET /api/oauth/authorize | Authorize proxy (strips offline_access before Supabase) |
scopes_supported on these documents includes openid, email, profile, and offline_access. Supabase still issues access and refresh tokens at token_endpoint; the proxy only adjusts the authorize redirect because Supabase rejects offline_access as an authorize scope today.
Protected-resource metadata and WWW-Authenticate challenges intentionally omit offline_access (per MCP SEP-2207).
After deploying discovery changes, delete and recreate your ChatGPT connector so it refetches metadata (OpenAI help article).
Unauthenticated POST /api/mcp requests return 401 with a WWW-Authenticate challenge pointing at the host-root MCP metadata URL.
At Supabase authorize time, clients (including ChatGPT) must request only standard OIDC scopes: openid, email, and profile. Protected-resource metadata, WWW-Authenticate challenges, and per-tool MCP securitySchemes from tools/list all advertise those OIDC scopes. Do not send Vings data scopes (for example wallets:read) in the authorize scope parameter — Supabase rejects them with invalid_request.
Vings data scopes are stored on the OAuth client when you create it in Vings settings and shown on the consent screen at /oauth/consent. After the user approves, scopes are saved in external_authorization_grants and enforced on REST routes and MCP tools by resolving the OAuth token’s client_id claim to that grant.
Vings scopes
For OAuth access tokens, the external API loads granted Vings scopes from the user’s consent record (keyed by JWTclient_id). If the token also includes vings_scopes, scope, or scopes claims with Vings values, enforcement uses the intersection of JWT claims and the consent grant. PATs always include scoped access directly on the token.
| Scope | Access |
|---|---|
profile:read | User profile |
transactions:read | Transactions |
cashflow:read | Cashflow summaries |
spending:read | Spending aggregates |
budgets:read | Budgets |
banks:read | Connected banks status |
wallets:read | Wallet-related data |
portfolio:read | Portfolio |
preferences:read | Preferences |
OpenAPI security
The live OpenAPI document definesbearerAuth (http + bearer). Use the API Reference playground: enter your token in the auth control, then call GET /v1/me to verify.
Security practices
- Do not send tokens in query strings or logs.
- Financial responses are not cached (
Cache-Control: no-store). - Per-user rate limits apply to REST and MCP; transaction search and portfolio endpoints have stricter limits than aggregate routes.
- This API exposes only user-scoped read access—no admin or service credentials.