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 withhttps://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 Also generate a random
code_verifier (43 to 128 characters), then derive the challenge:state string to protect against CSRF.2
Redirect the user to the authorize endpoint
%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: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 Access tokens are valid for 1 hour. Refresh tokens are valid for 30 days and rotate on every use.
application/x-www-form-urlencoded, not JSON:4
Call the API
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.
limit is null once approved.
Good to know
The token endpoint is form-urlencoded
The token endpoint is form-urlencoded
Per the OAuth spec,
/oauth/token expects application/x-www-form-urlencoded. Sending JSON fails with invalid_client.Redirect URIs match exactly
Redirect URIs match exactly
No wildcards, and
https://yourapp.com/callback is not the same as https://yourapp.com/callback/.Users can revoke your app at any time
Users can revoke your app at any time
From their Synci settings. All of its tokens stop working immediately and the user must authorize again.
Suspended apps are cut off immediately
Suspended apps are cut off immediately
Existing tokens are rejected and refresh is blocked.
Request minimal scopes
Request minimal scopes
Users are more likely to approve an app that asks only for what it needs, and reviews go faster.