Skip to main content
OAuth apps let other Synci users grant your application access to their financial data. Unlike a personal access token (which only reaches your own account), an OAuth app uses a consent flow: the user reviews the permissions you request, picks which accounts to share, and can revoke access at any time. Synci implements OAuth 2.0 authorization code grant with PKCE.

Which kind of app do you need?

Two self-serve app types share this API. You pick one when you create the app, and the choice is permanent: it decides who is billed for every bank connection the app creates. Standard is the right default: if the people you are building for already have Synci accounts, or would happily create one, this guide is all you need. Managed users exists for products that want bank connections embedded in their own experience, where sending people off to create a Synci account would lose them. See Managed apps. The flow is quite different from the one below. Building at high volume, or want a commercial arrangement other than a standard plan (usage-based billing, for example)? Those are done by agreement rather than self-serve: get in touch. The rest of this guide covers Standard apps.

Register your app

In the Synci dashboard, go to Developers → Apps → New app. You will set:
  • Name: shown to users on the consent screen.
  • Redirect URIs: up to 5 exact-match https:// URLs where Synci sends users back after they approve. No wildcards, no trailing-slash differences. While your app is in testing, http:// is also allowed for loopback hosts (localhost, 127.0.0.1, ::1) so you can develop locally; loopback URIs must be replaced with https:// before you submit for review.
  • Permissions (scopes): the scopes your app may request. On any given authorization you can request a subset, never more. See the scope table in Authentication.
  • Branding: developer or company name, description, homepage, privacy policy, and logo. Required before you can submit for review.

Client credentials

Every app is a confidential (server-side) client:
  • Client ID: public identifier, safe to embed in URLs.
  • Client secret: shown once at creation. Store it securely on your server and never expose it in a browser or mobile app. You can rotate it at any time (the previous secret stops working immediately).
Public or PKCE-only clients (browser-only or mobile apps without a backend) are not currently offered. If you need one, get in touch.

The authorization flow

1

Generate PKCE values and state

Create a random code_verifier (43 to 128 characters), then derive the challenge:
Also generate a random state string to protect against CSRF.
2

Redirect the user to the authorize endpoint

Scopes are space-separated (URL-encoded as %20) and must be a subset of the scopes your app is registered for.The user signs in, reviews your app’s branding and the requested permissions, and, when account-scoped permissions are requested, selects which accounts your app may access. Users approve the request as a whole; they cannot deny individual scopes.On approval, Synci redirects back to your redirect URI:
Verify that state matches what you sent before continuing. The code is single-use and expires after about 10 minutes.On denial, the redirect carries ?error=access_denied instead of a code.
3

Exchange the code for tokens

From your backend, POST to the token endpoint. The body must be application/x-www-form-urlencoded, not JSON:
Access tokens are valid for 1 hour. Refresh tokens are valid for 30 days and rotate on every use.
4

Call the API

The token can reach exactly what the user approved: requests outside the granted scopes return 403, and accounts the user did not select return 404.
5

Refresh tokens

When the access token expires, exchange the refresh token (again form-urlencoded):
Each refresh returns a new access token and a new refresh token. Always store the newly returned refresh token; the one you just used is invalidated.

App review lifecycle

You can return an approved app to development at any time; this unpublishes it without revoking existing user connections. Deleting an app or rotating its secret requires password confirmation in the dashboard.

The pre-review limit

An app that has not been reviewed is open to anyone, but only up to 10 people besides you. That is enough to run a real beta, and it bounds how far an unvetted app can reach before Synci has looked at it.
  • You never consume a slot, so 10 means 10 other people.
  • Revoking frees a slot, and an abandoned authorization frees one when its refresh token lapses.
  • Someone who already authorized can always re-authorize, even at the limit.
  • Approval removes the limit entirely, and existing authorizations carry over.
Once the limit is reached, a new user sees an “app isn’t taking new users yet” page rather than your consent screen. Your app payload reports where you stand:
limit is null once approved.

Good to know

Per the OAuth spec, /oauth/token expects application/x-www-form-urlencoded. Sending JSON fails with invalid_client.
No wildcards, and https://yourapp.com/callback is not the same as https://yourapp.com/callback/.
From their Synci settings. All of its tokens stop working immediately and the user must authorize again.
Existing tokens are rejected and refresh is blocked.
Users are more likely to approve an app that asks only for what it needs, and reviews go faster.

Common errors