Skip to main content
Every Spritz user belongs to your integration. Onboarding has three beats: create the user, verify their identity, and read their capabilities to see what they can do. If the person already has a Spritz account, with you or with another integrator, you don’t create a new user. You connect to them instead, with their consent.

1. Create a user

Create a user with their email address. Spritz returns a user API key (prefixed ak_) that you use to authenticate requests on that user’s behalf.
Store the apiKey securely. You send it as the Authorization bearer for every request you make on this user’s behalf (see Authentication). You can also pass an optional timezone.

2. Verify identity

Before a user can move money, they complete identity verification (KYC). Start a verification session for the user:
The response selects the provider for this session. Do not hard-code one provider: provider is either persona or plaid, and both sessionToken and verificationUrl are nullable. Use this dispatch contract: Prefer the provider SDK when you support it and a token is present; otherwise use the hosted URL. A non-null verificationUrlExpiresAt is authoritative. If that time has passed, create another session instead of opening the old URL. When it is null, still request sessions just in time and never persist a URL as a permanent verification link. Persona SDK references: Web embedded flow, React Native and native mobile. Plaid sessions use the same Plaid Link client integration described by Plaid’s SDK documentation; the token comes from this verification-session response, not from the bank-account link-token endpoint. Creating a session can also return 409. Branch on its stable code, never its title or detail: The user’s verification state is reported on their profile as verification.status: not_started, verified, failed, retry, or disabled. A retry status means they can try again; create a new session to do so.

3. Read capabilities

GET /v1/users/me returns the user’s verification status and their capabilities. Capabilities are the source of truth for what a user can do right now, and what’s blocking anything they can’t.
For an ACH-debit-enabled integrator, a verified US user receives the active fiat_to_crypto / ach_debit capability with no separate terms requirement. Other products and regions can still return requirements_needed; always drive the UI from the actual capability object instead of assuming every method has the same gates. Select ACH debit by the exact pair, not by array position or display name:
method is optional in the generic capability schema because non-ramp products do not have a transfer method. A missing method does not match ACH debit. If no capability has the exact pair above, treat ACH debit as not_available: do not start bank linking, and offer another supported deposit method. Each capability is a product, and for ramps a method:
  • Products: fiat_to_crypto, crypto_to_fiat, bill_pay, crypto_card
  • Methods: ach_credit, ach_debit, wire, sepa_credit_transfer, rtp, push_to_card, canadian_eft
Its status tells you where it stands: For the ACH debit entry point, use this minimum copy and action contract: “Contact support” means the integrator’s configured in-app support route. Its support team escalates to Spritz; do not invent a direct Spritz operations URL. When a capability is requirements_needed, its requirements[] lists what to do. type and status are always present. description, actionUrl, retryable, and the capability’s nextRequirement are optional by contract. Choose the requirement whose type equals nextRequirement when that field is present and still incomplete. Otherwise choose the first requirement whose status is not completed. If there is no such requirement, re-fetch the user once. If the capability still says requirements_needed with no incomplete requirement, show “We couldn’t load the next verification step.” with Contact support; do not guess a step. Use a returned description when present. Otherwise use this fallback and action matrix: When actionUrl is present, open it for every non-terminal requirement, then re-fetch the user after the flow returns. A missing retryable is not permission to retry a failed provider action automatically. Only retry when it is true or when the explicit type/status handling above gives the user a retry action.

Drive your UI from capabilities

Render your onboarding and product UI off the capabilities list rather than tracking state yourself:
  • Show a capability as available when its status is active.
  • When it’s requirements_needed, select and render the requirement using the fallback rules above. Never assume its optional presentation or action fields are present.
  • After the user completes a requirement, re-fetch GET /v1/users/me, or react to the capabilities.updated webhook so you update without polling.

Connect an existing Spritz user

If the person already has a Spritz account, with you or with another integrator, use Integrator Connect to gain access with their consent instead of creating a new user. It’s an OAuth-style authorization flow.
1

Create a connect session

From your backend, create a session with a pre-registered HTTPS redirect URI and an optional state value you can use to tie the result back to a request.
2

Send the user to approve

Redirect the user to authorizationUrl. They sign in to Spritz, review your integration, and approve. The session is valid for about 10 minutes.
3

Receive the authorization code

On approval, Spritz redirects the user back to your redirectUri with a code and the state you sent.
4

Exchange the code for a user key

From your backend, exchange the code for that user’s API key. The code is single-use and expires after a few minutes.
You now hold a user API key for that user and can act on their behalf, exactly like a user you created.

Next

Authentication

Use the user API key to sign requests.

What we support

Rails, tokens, and regions behind each capability.

Off-ramp

Put an active capability to work.

Webhooks

React to capabilities.updated and verification changes.