OAuth data sync
Overview
Use OAuth data sync to push bank data into a customer's stub business. The customer starts the connection in your portal, signs in to stub, selects a business, and grants consent.
stub never receives banking credentials or accesses banking screens.
How it works
You are a confidential OAuth client of stub's authorisation server. Your client secret is required whenever you issue, refresh, or revoke a token. Access tokens only authorise data sync requests.
Link a customer
Send the customer to stub's consent page. They sign in, select a business, and approve the connection. stub redirects them to a registered return address with a single-use authorisation code.
After approval, stub redirects the browser to your redirect_uri with code and state. If the customer declines, the redirect contains error=access_denied and state. It does not contain a code.
Get tokens
Exchange the authorisation code from your server. Include the client secret in the request body or an HTTP Basic header. The secret is also required for token refreshes and revocations.
To refresh a token, send grant_type=refresh_token, refresh_token, client_id, and client_secret.
The access token identifies one business. Each request applies to that business. Request payloads do not contain a business field.
Register accounts
Register the accounts the customer chose to share. Send a stable bank account ID in externalid. stub uses this value for matching and returns a bankaccountid for each account.
If a customer already added an account manually or through an aggregator, stub adopts it instead of creating a duplicate. When the externalid is one stub has not seen, it matches on the account number — but only against an account that is not already claimed by another externalid. An account already registered by another source is left alone. This request is idempotent. Send it again whenever the shared accounts change.
Push transactions
Send posted transactions only. stub validates each row on receipt and returns rejected rows in the response.
Treat any 2xx as accepted. This endpoint returns 202 when the accounting write is queued, and 200 when it completes while you wait. Which one you get depends on how the environment you are calling is configured, so do not branch on the exact code. A 202 response additionally means the batch is not yet written — use the receipt to find out what became of it.
Use GET /api/datasync/receipt/{receipt} to check a batch status. It returns accepted, ingested, declined, or failed. Use it after a timeout when the delivery result is uncertain.
Resolve rejected rows
externalid is required
Include a stable transaction ID. stub uses it to identify resubmissions.
date must be yyyy-MM-dd
Posting date, no time component. Use datetime for the timestamp.
value (or debit/credit) is required
Send a signed value, or a debit/credit pair.
value may not be zero
A zero-amount row is not a movement of money.
description is required
Include the statement narrative shown to the customer.
A rejected row does not fail the batch. stub retains rejected rows for 30 days. An operator can return or replay a corrected row.
Send at most 5,000 rows per request. Larger requests return 413 and write nothing. Split daily batches and backfills into smaller requests.
Handle retries and balances
Duplicate rows do not create duplicate transactions. Repeating a request with the same idempotency key returns the original response.
The same row again
Its externalid already exists
stub records it as a duplicate. Nothing is written.
The same request again
Your Idempotency-Key matches one from the last 24 hours
stub returns the stored response. The handler does not run.
An Idempotency-Key can contain up to 128 characters. Longer keys return 400. stub does not truncate keys.
End a connection
Either side can end a connection. stub operators cannot end connections.
Revoke a connection
The endpoint returns 200 for unknown and already-revoked tokens. This prevents token discovery.
Handle customer revocations
Customers can disconnect your bank app in stub. stub then sends a signed webhook so you can stop pushing data.
Verify the signature with your client secret. No additional shared credential is required. Return 2xx to acknowledge the webhook. stub retries timeouts and 5xx responses three times with increasing delays. It does not retry 4xx responses.
Access tokens remain valid for their one-hour lifetime. Transaction writes check the connection's revocation status. Transactions cannot be written after revocation. Account registration can still succeed during that hour.
Responses
200
Accounts were written, or a transaction batch was written while you waited
Store the bankaccountid values. For transactions, created and duplicates are in the body.
202
Transaction batch was accepted and is not yet written
Store the receipt. Review rejected rows in the body.
400
Request is malformed or Idempotency-Key is too long
Check the response body.
401
Token is missing, expired, or invalid
Refresh the token and retry once.
403
Customer revoked the connection
Stop pushing for that business. Do not retry.
413
Request contains more than 5,000 rows
Split the batch.
429
stub is saturated
Honour Retry-After and back off.
503
A stub operator paused data sync
Honour Retry-After. Tokens remain valid. Retry later.
Before go-live
Provide the exact return addresses and unlink webhook URL. Both must use HTTPS.
Store the client secret when it is issued. It is shown once. Two secrets can be active during rotation.
Verify the webhook. stub sends a signed test request and records your response.
Last updated
