Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.vin.gs/llms.txt

Use this file to discover all available pages before exploring further.

Build a personal dashboard that reads your Vings data through the External API. Use v0, Lovable, or any stack you control. This path uses OAuth + REST (/api/v1/*). It is not the MCP integration used for ChatGPT and Claude connectors.

What you get

PieceValue
API basehttps://external.vin.gs/api
OpenAPIhttps://external.vin.gs/api/openapi.json
OAuth discoveryGET /api/.well-known/oauth-protected-resource
Vings setupDashboard → SettingsIntegrationsPersonal dashboards
Personal dashboard OAuth clients are owner-only: only the Vings user who created the client can approve consent. They are public clients (PKCE, no client secret).

Reference implementation

Use this public v0 example app as the canonical pattern for OAuth (PKCE), httpOnly cookies, and server-side API proxies: github.com/chriskrogh/v0-personal-finance-dashboard When building with v0 or Lovable, point your agent at that repository (and this guide) instead of inventing routes or field names from scratch.

Setup steps

  1. Deploy or preview your app with a fixed HTTPS callback path (for example https://your-app.vercel.app/auth/callback). Localhost callbacks are also allowed when registered.
  2. Copy the callback URL from your deployment (scheme, host, path, and trailing slash must match exactly).
  3. In Vings, open Settings → Integrations → Personal dashboards, choose Add dashboard, paste the redirect URI, and copy the Client ID.
  4. Set VINGS_OAUTH_CLIENT_ID in your project to that Client ID.
  5. Discover OAuth endpoints — fetch GET /api/.well-known/oauth-protected-resource, then GET {authorization_servers[0]}/.well-known/openid-configuration. Use authorization_endpoint and token_endpoint from that JSON (see OAuth flow).
  6. PKCE sign-in — public client, S256 code_challenge, scopes openid email profile; exchange the authorization code at the token endpoint with code_verifier (no client secret). After login, approve access on /oauth/consent.
  7. Proxy API calls server-side — browser apps cannot call external.vin.gs directly (CORS). Add Next.js (or similar) routes that attach the bearer token, then call your proxy from the client.
  8. VerifyGET /v1/me through your proxy. Use REST only — not MCP.

Give your builder the right instructions

On the Personal dashboards settings page, open the v0 or Lovable tab and copy the platform-specific agent prompt into your project instructions or project knowledge. It links back to this guide and the live OpenAPI document so the agent does not invent endpoints or use MCP by mistake.

v0

  • Paste the v0 agent prompt into project instructions before scaffolding OAuth.
  • Add the reference implementation repo URL so the agent can mirror working routes.
  • Add VINGS_OAUTH_CLIENT_ID in the project environment.
  • If your preview or production URL changes, update the redirect URI in Vings and redeploy.

Lovable

  • Paste the Lovable agent prompt into project knowledge so generated code uses REST, not MCP.
  • Link the reference implementation in project knowledge.
  • Set VINGS_OAUTH_CLIENT_ID in env or secrets.
  • Re-check the redirect URI in Vings when Lovable changes your published domain.

OAuth flow

Common mistake: Personal dashboard OAuth uses /auth/v1/oauth/authorize and /auth/v1/oauth/token. Do not use /auth/v1/authorize or /auth/v1/token — those are for Google/Apple social sign-in and return errors like Unsupported provider: Provider could not be found.
Expected full URL shapes (issuer varies per environment):
Authorization: https://{issuer-host}/auth/v1/oauth/authorize
Token:         https://{issuer-host}/auth/v1/oauth/token
Always prefer the authorization_endpoint and token_endpoint values from OpenID discovery rather than guessing paths.

Discovery

Step 1 — protected resource metadata:
curl -sS https://external.vin.gs/api/.well-known/oauth-protected-resource
Read authorization_servers[0] as the OAuth issuer (Vings Supabase Auth base, typically ending in /auth/v1). Step 2 — OpenID configuration:
curl -sS "{authorization_servers[0]}/.well-known/openid-configuration"
Use the authorization_endpoint and token_endpoint fields from that JSON verbatim in your authorize and token requests. Manual fallback (only if you cannot read discovery): append /oauth/authorize and /oauth/token to the issuer from step 1 — for example {issuer}/oauth/authorize. Do not append bare /authorize or /token.

Public client + PKCE

Vings registers personal dashboards as public clients with token_endpoint_auth_method: none. Your app must:
  • Generate a code_verifier / code_challenge (S256) for each sign-in.
  • Send client_id, redirect_uri, response_type=code, code_challenge, and code_challenge_method=S256 to the OAuth authorization endpoint.
  • Exchange the authorization code at the token endpoint with code_verifier (no client secret).
At authorize time, request standard OIDC scopes (openid, email, profile). Vings data scopes (for example portfolio:read, transactions:read) are attached to the OAuth client when you create it in settings and are shown on the Vings consent screen at /oauth/consent. After the user signs in to Vings (if needed), they approve readonly access on the Vings consent page. If someone other than the client owner tries to authorize a personal dashboard client, consent is rejected. Store OAuth state and code_verifier in httpOnly cookies before redirecting to the authorization endpoint. After token exchange, store the access token the same way (not localStorage in production).
  • httpOnly: true — tokens are not readable from client JavaScript.
  • sameSite: "lax" (not "strict") — cookies are sent when the identity provider redirects back to your callback.
  • secure: true in production (HTTPS).
  • Short maxAge for state and verifier (for example 10 minutes).
See the reference implementation for a working Next.js layout (/auth/login, /auth/callback, and cookie names).

Server-side API proxy (required for browser apps)

The External API does not allow direct browser requests (CORS). Every dashboard UI should call your own server routes, which forward requests with Authorization: Bearer <access_token>.
  • Create one route file per upstream endpoint (for example /api/vings/me, /api/vings/transactions).
  • Read the access token from your httpOnly cookie on the server, then fetch https://external.vin.gs/api/....
  • Do not use catch-all proxy routes like app/api/vings/[...path]/route.ts — they can return 404 or behave inconsistently on some hosts.
  • From the browser, call only your /api/vings/* routes — never https://external.vin.gs/api/... directly.
The reference implementation shows this pattern end to end.

Call the API (server or curl)

GET https://external.vin.gs/api/v1/me
Authorization: Bearer <access_token>
Verify with GET /v1/me, then add endpoints for the widgets you need. See Authentication for scopes and Introduction for the full REST list. Example (after you have a token):
curl -sS https://external.vin.gs/api/v1/portfolio \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Common field names

The OpenAPI spec is authoritative. These names differ from what many agents guess:
You might expectActual name / notes
amountamount_cents (integer; divide by 100 for display)
limitpageSize (query param on GET /v1/transactions)
merchantmerchant_name on transaction objects
descriptiontitle on transaction objects
is_incometype"INCOME" or "EXPENSE" (also INTERNAL_TRANSFER)
categorycategory — uppercase enum (for example GROCERIES, RENT)
Money totalsObject { amount_cents, currency } (not a bare number)
Next pagepagination.nextCursor and pagination.hasMore (not page numbers)
Min/max filtersminAmountCents, maxAmountCents (query params, in cents)
Merchant searchmerchantQuery (query param, not merchant)

Suggested dashboard endpoints

GoalEndpoint
Sanity checkGET /v1/me
Net worth / holdingsGET /v1/portfolio, GET /v1/portfolio/history
Spending overviewGET /v1/spending/summary, GET /v1/spending/categories
Recent activityGET /v1/transactions
Budget progressGET /v1/budgets/summary
CashflowGET /v1/cashflow/summary
Use OpenAPI for parameters and response shapes. Do not expose tokens in query strings, logs, or client-side analytics.

Prototype without OAuth (optional)

For local experiments only, you can use a personal access token (vng_pat_*) created under Settings → Integrations → API keys. PATs are for scripts and quick tests—not for shipping a multi-user hosted dashboard. Production personal apps should use OAuth.

Security practices

  • Treat the access token like a password; never commit it or pass it in URLs.
  • Responses are user-specific and use Cache-Control: no-store.
  • The External API is read-only; no writes or bank linking through this API.
  • Revoke the OAuth client in Vings settings to cut off access immediately.
  • Do not use MCP (/api/mcp) for v0/Lovable dashboard UIs unless you are explicitly building an MCP host.

Troubleshooting

SymptomWhat to check
Unsupported provider: Provider could not be foundWrong authorize URL — use OIDC authorization_endpoint (/auth/v1/oauth/authorize), not /auth/v1/authorize.
redirect_uri mismatchRedirect in the authorize request must exactly match a URI registered on the personal dashboard client.
Consent says the app is privatePersonal dashboards only work for the Vings user who created the client.
401 on API callsMissing or expired bearer token; repeat sign-in.
Empty portfolio or spendingUser may have no linked accounts yet; handle empty states in the UI.
CORS errors from the browserDo not call external.vin.gs from the browser — add server-side proxy routes (see reference implementation).
Callback route returns 404Use explicit API route files per endpoint, not catch-all [...path] proxies (see example repo).
State mismatch on callbackOAuth cookies lost on redirect — use sameSite: "lax", httpOnly: true, and secure: true in production.
amount is undefined in UIResponse field is amount_cents; divide by 100 for dollars.
No transactions returnedQuery param is pageSize, not limit — e.g. GET /v1/transactions?pageSize=5.