Skip to main content
A Managed app lets you offer bank connections inside your own product to people who do not have a Synci account and never will. You register each of your users with Synci through a server-to-server API, send them to a hosted portal to connect their bank, and then read their financial data with a token scoped to that one person. You pay for their connections out of your own Synci plan. They never see Synci branding beyond the portal, never create a password, and never get a bill.
If your users already have (or would happily create) their own Synci accounts, you want a Standard OAuth app instead: it is simpler, and they pay for their own connections.

How it fits together

Two separate surfaces are involved, and it is worth keeping them straight: The Managed Users API has its own reference: Managed Users API.

Create the app

In the Synci dashboard, go to Developers → Apps → New app and choose Managed users as the app type.
The choice is permanent. It decides who is billed for every connection the app creates, so it cannot be changed afterwards. If you pick wrong, create a new app.
You get a client ID and a client secret (shown once, prefixed oac_). Both are used as HTTP Basic credentials on the Managed Users API. Store the secret on your server; it is never safe in a browser or a mobile binary. A Managed app has no redirect URIs; the field is rejected. Nobody is sent through an OAuth consent screen, so there is nowhere to redirect to. What you configure instead is a portal return URL (see App settings).

What a Managed app may request

A Managed app is restricted to bank-data scopes. These eight and no others: profile:read · accounts:read · accounts:write · transactions:read · transactions:write · sensitive:read · financial-connections:read · financial-connections:write Rules, transfer links, destinations and webhooks are deliberately out of reach: those are consumer-product features that belong to a Synci account, and your users do not have one. See the scope table in Authentication.

Connect a user, end to end

1

Authenticate to the Managed Users API

Standard HTTP Basic. Your client ID is the username, your client secret is the password.
Rate limits are 300 requests/minute per client and 600/minute per source address. Errors carry error and message keys.
2

Register the user

201 Created returns the user and their first token pair, unwrapped at the top level.user_id is an opaque UUID with no relationship to Synci’s internal identifiers, and it is scoped to your app. It is the id you use everywhere else. Asking for another developer’s user returns 404, identical to asking for one that does not exist.Registration is atomic: if the token cannot be issued, the user is not created.
3

Send them to the portal

Your user connects their bank in Synci’s hosted connection portal. You do not build this, and you never touch their bank credentials.Mint a single-use link:
Send the user to url. They arrive already signed in, with no password, no code and no Synci account.
The Synci connection portal showing the app's name, a bank picker, and the user's connected accounts.

The Synci connection portal, as your user sees it.

Your app’s name and logo appear here once it is approved; until then the portal tells the user it has not been reviewed yet and shows an initial avatar instead.
The link lives 10 minutes and is strictly single-use. Mint it at the moment you are about to redirect, not in advance. A replayed link is dead.
return_url is optional. Provide it to override the app default for this one visit, which is useful when you know which of your screens they left from. Omit it to use the app’s configured portal_return_url.An expired link degrades gracefully. The app id rides along in the URL, so a user who opens a stale link is offered an emailed sign-in code by the portal instead of hitting a dead end. Nothing for you to build; see When a link expires.
4

Read their data

Use the access token from registration. It is an ordinary Bearer token against the normal API:
The token reaches only that user’s data, and only within your app’s scopes. Everything outside those scopes returns 403; another user’s data returns 404.Unlike a Standard app (where the user picks which accounts to share on a consent screen), a Managed app’s token sees every account that user connects, including ones connected later. There is no account picker in this lane; you registered them, and the grant is implicit in that.Sensitive identifiers (IBAN, account and card numbers, account holder names) are redacted unless your app holds sensitive:read. This is enforced server-side and cannot be switched off by the caller.
5

Mint fresh tokens as needed

Access tokens last 1 hour, refresh tokens 30 days. Refresh normally, or mint a new pair at any time:
A user_id that is not one of your users returns 400 with "error": "invalid_request"; the specific reason is in the hint field, not error_description.
Portal links live 10 minutes, and people do not always click them in 10 minutes. Rather than showing a dead end, the portal offers to email that user a six-digit sign-in code, scoped to your app. They enter it and land in the same place the link would have taken them. There is nothing to build and nothing to call. The portal owns this entirely: it decides when to offer a code, sends it, and handles the retries. Your part is already done when you mint the link, because the app id travels in the URL and is what lets the portal scope the code to your app rather than to the address in general. Two things follow from it that are worth knowing:
  • A user who lets a link expire is not stuck. You do not need to detect it or mint a replacement, though minting a fresh link is always safe if your own UI is bringing them back anyway.
  • email_verified flips to true when someone redeems a code, and only then. A link you minted never sets it: you vouching for an address is not evidence that the person controls that mailbox, and the field would be worthless if it said otherwise. Read it as “has proven they can read this inbox”, not as “we checked the address is valid”.

Managing users

Request and response schemas for each are in the Managed Users API reference.

See every connection at once

Rather than polling each user, list every connection your app pays for. This is not bank-only: your users’ brokerage and crypto-exchange connections come back here too, and the provider filter is how you narrow to one kind.
Filters: user_id, external_user_id, status, provider, expiring_within_days, per_page.
expiring_within_days is the one to build on. Under PSD2 a bank consent lapses every 90 to 180 days, so a nightly ?expiring_within_days=14 sweep tells you exactly who needs to re-authorize before anything breaks.

App settings

All Managed-only, all in Developers → Apps → your app, and all take effect immediately: none are review-gated. The portal filters its bank picker on providers and countries, so a user never sees an institution they cannot connect.

Before you turn off “email your users”

Synci’s expiry emails are a large part of what you get here. A bank consent lapses every 90 to 180 days, and someone has to tell the user and give them somewhere to re-authorize. Off means that is yours to do.
There are no connection-lifecycle webhooks yet, so “handle it yourself” means polling GET /managed/v1/connections?expiring_within_days=... and building your own re-consent prompt. Left on, your users get the mail, it names your app, and the link drops them straight into the portal to fix it.

Billing

You pay for a Managed app the same way every other Synci customer pays: a Basic or Pro subscription on your own account, priced per bank connection. There is no separate developer invoice and nothing to reconcile. Your subscription quantity is a single pool, shared between your own personal bank connections and every connection your users create across every Managed app you own. Buy 50, and your users can hold 50 between them. Registering users is free. You only pay when one of them actually connects a bank. Up to 200 connections are self-serve. Beyond that, or if you would rather be billed monthly on actual usage than prepay a quantity, get in touch: those are commercial agreements rather than something you can set up yourself. When a connection is refused, the code tells you which ceiling you hit:

Review and going live

To submit for review you need developer_name, homepage_url and privacy_policy_url set, and an active Synci plan. Paying lifts the trial cap immediately, reviewed or not: you bought the slots. Until you are reviewed, the portal tells your users so and falls back to an initial avatar rather than your logo. An unvetted image never reaches a user.

Your users are yours

  • Deleting a user is real, and it frees their email address for re-registration.
  • They can revoke a bank connection themselves from the portal at any time.
  • They are not a Synci account. They cannot log in, cannot be reached by Synci sales, and see no Synci dashboard.
  • If your app is suspended or removed, Synci emails them once to say your app can no longer access their bank connections.

Common errors

Support

Email support@synci.io. Include your client ID (never your secret) and, where relevant, the user_id. Both are safe to quote.