payout / developers
API reference

PayoutID API

PayoutID is Payout's OAuth2 and OpenID Connect provider and identity verification service.

  • OAuth2 – redirect users to PayoutID for authorization, then exchange the result for an access token. Tokens can also be refreshed, or issued to your own client with client credentials.
  • Verifications – create identity verification invitations for your customers and receive the results by webhook.

Guides: OAuth2 and identity verification.

Environments

EnvironmentBase URL
Sandboxhttps://id-sa.payout.one
Productionhttps://id.payout.one

Authentication

Payout registers your application as a PayoutID client and gives you a client_id (a UUID) and a client_secret. The client also holds your registered redirect URIs and the scopes you may request.

Token endpoint

Authenticate your client at Get access token with one of these methods:

  • client_secret_basic – HTTP Basic authentication with client_id as the user name and client_secret as the password
  • client_secret_post – client_secret as a body parameter
  • client_secret_jwt – a JWT signed with your client secret, sent in client_assertion
  • private_key_jwt – a JWT signed with your private key, sent in client_assertion

client_secret_basic and client_secret_post are enabled for every client by default. The JWT methods work only if Payout configured them for your client. Always send client_id in the body as well.

Verifications API

Send the access token from the token endpoint in the Authorization header:

HTTP
Authorization: Bearer <access_token>

Access tokens are JWTs signed by PayoutID. A token works only in the environment that issued it: https://id-sa.payout.one for Sandbox, https://id.payout.one for Production.

Errors

How an error is reported depends on the endpoint.

Token endpoint errors

Get access token returns errors as JSON with error and error_description:

JSON
{
  "error": "invalid_grant",
  "error_description": "Given authorization code is invalid, revoked, or expired."
}

The HTTP status is 400, except for invalid_client (401) and unknown_error (500). Error codes:

  • invalid_request – a parameter is missing or malformed, or the PKCE code verifier is wrong
  • invalid_grant – the authorization code or refresh token is invalid, revoked or expired
  • invalid_scope – a requested scope is not enabled for your client or not allowed for this grant
  • unsupported_grant_type – the grant type is not enabled for your client
  • invalid_client – unknown client, wrong client secret, or a redirect_uri that does not match
  • unknown_error – unexpected server error

Authorization redirect errors

Authorize user reports errors by redirecting the browser to your redirect_uri with error and, when available, error_description and state. Codes you can expect:

  • access_denied – the user denied access
  • invalid_scope – a requested scope is unknown, not enabled for your client, or cannot be combined with the other requested scopes
  • invalid_request – the request is invalid, for example code_challenge is missing although PKCE is enabled for your client
  • login_expired – the login page expired before the user logged in

If client_id or redirect_uri is invalid, PayoutID cannot redirect back safely and shows an error page to the user instead.

Verifications API errors

  • 403 – the token is missing, invalid or expired, or lacks scope verify. The body is the plain text UNAUTHORIZED: Missing or insuficient authorization, although the Content-Type header says application/json.
  • 422 – validation failed. The body is JSON with the messages by field: {"errors": {"<field>": ["<message>"]}}.
GET

Authorize user

/oauth/authorize

Starts the authorization code flow. Open this URL in the user's browser: it is a page, not an API call.

Authorization flow

  1. PayoutID asks the user to log in or register, if needed.
  2. The user approves the requested scopes.
  3. PayoutID redirects the browser to redirect_uri with code and state. If the user denies access or the request fails, the redirect carries error instead (see Authorization redirect errors).
  4. Exchange code for tokens with Get access token and grant_type=authorization_code. The code is valid for at most 60 seconds and works only once.
Redirect the browser to
https://id-sa.payout.one/oauth/authorize?client_id=c24760a3-134f-4ff5-891b-e506a025a530&response_type=code&redirect_uri=https://www.example.com&scope=openid%20profile&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&state=c0416c89-02fb-4c64-b4f6-9ebee510f4a0

Parameters

client_id requiredquery · string<uuid>

Your client ID.

Example c24760a3-134f-4ff5-891b-e506a025a530
response_type requiredquery · string

Selects the authorization code flow.

One of code
redirect_uri requiredquery · string

Where to send the user back. Must match a redirect URI registered for your client.

Example https://www.example.com
scopequery · string

Space-separated scopes to authorize. Each scope must be enabled for your client. Include openid to also get an id_token.

Example openid profile
code_challengequery · string

PKCE code challenge, derived from your code_verifier as set by code_challenge_method (RFC 7636). Required when PKCE is enabled for your client.

Example E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
code_challenge_methodquery · string

How code_challenge is derived from code_verifier. Use S256.

  • S256code_challenge is the unpadded BASE64URL encoding of the SHA-256 hash of code_verifier
  • plaincode_challenge is code_verifier itself
Default plain · Example S256
statequery · string

Returned unchanged in the redirect to redirect_uri, so you can match the response to your request.

Example c0416c89-02fb-4c64-b4f6-9ebee510f4a0

Responses

302

Redirects the browser to the PayoutID login and consent pages, and finally back to redirect_uri.

POST

Get access token

/oauth/token

Issues an access token to your client. grant_type selects what you exchange for it and which other parameters you send.

Authenticate your client as described in Authentication. To call Create invitation, use client_credentials with scope verify.

The body can be application/x-www-form-urlencoded or JSON.

Request
curl -X POST 'https://id-sa.payout.one/oauth/token' \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
       "grant_type": "authorization_code",
       "client_id": "c24760a3-134f-4ff5-891b-e506a025a530",
       "code": "63a74bf4-fa3d-4b21-8350-8c51ae47d74a",
       "redirect_uri": "https://www.example.com",
       "code_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
     }'
Response 200
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9.eyJpc3MiOiJodHRwczovL2lkLXNhLnBheW91dC5vbmUifQ.…",
  "token_type": "bearer",
  "expires_in": 86400,
  "refresh_token": "4b217f27-836a-4a12-97a3-b962c23dedc5"
}

Request body

grant_type requiredstring

What you exchange for the token.

  • authorization_codeExchange the code from Authorize user. Send code and redirect_uri, plus code_verifier when PKCE is enabled for your client. Client authentication is required for a confidential client.
  • refresh_tokenGet a new access token with refresh_token, optionally for fewer scopes with scope. Client authentication is required unless public refresh is enabled for your client.
  • client_credentialsGet a token for your own client, without a user, optionally with scope. Client authentication is required.
client_id requiredstring<uuid>

Your client ID. Send it in the body even when you authenticate with HTTP Basic.

Example c24760a3-134f-4ff5-891b-e506a025a530
client_secretstring

Your client secret, for client_secret_post. Omit it when you authenticate with HTTP Basic.

codestring

The code from the authorization redirect. Required for authorization_code.

Example 63a74bf4-fa3d-4b21-8350-8c51ae47d74a
redirect_uristring

The same redirect_uri as in the authorization request. Required for authorization_code.

Example https://www.example.com
code_verifierstring

PKCE code verifier. Required for authorization_code when PKCE is enabled for your client.

Example dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
refresh_tokenstring

Refresh token from an earlier token response. Required for refresh_token. It works only once; the response carries a new one.

Example 4b217f27-836a-4a12-97a3-b962c23dedc5
scopestring

Space-separated scopes. With client_credentials, each must be enabled for your client, and PISPSUBMIT is not allowed. With refresh_token, at most the scopes of the original token, which are the default.

Example verify account_info
client_assertion_typestring

Only for clients configured for client_secret_jwt or private_key_jwt.

One of urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertionstring

Signed JWT, only for clients configured for client_secret_jwt or private_key_jwt. Set sub to your client ID and aud to the PayoutID URL of the environment. The iss and exp claims are required too.

Response 200

access_tokenstring

Access token (JWT). Send it as Authorization: Bearer <access_token>.

token_typestring

Token type.

One of bearer
expires_ininteger

Seconds until the access token expires.

Example 86400
refresh_tokenstring

Refresh token for the refresh_token grant.

id_tokenstring

OpenID Connect ID token (JWT). Returned by the authorization_code grant when the openid scope was granted.

Other responses

400

The request, grant or scope is invalid, or the grant type is not enabled for your client. See Token endpoint errors.

Example
{
  "error": "invalid_grant",
  "error_description": "Given authorization code is invalid, revoked, or expired."
}
401

Client authentication failed (invalid_client).

Example
{
  "error": "invalid_client",
  "error_description": "Invalid client_id or client_secret."
}
POST

Create invitation

/api/v1/verification/invitation on id-sa.payout.one · id.payout.one

Creates an identity verification invitation for one of your customers and returns the redirect_url to send them to.

Authenticate with a client_credentials access token that has scope verify (see Get access token).

Verification flow

  1. Create the invitation and redirect the customer to redirect_url.
  2. The customer completes the verification steps and is redirected to callback_url.
  3. When all data are collected, PayoutID sends the customer's details by webhook to notify_url, and the AML check results to aml_notify_url.

The identity verification guide describes the webhooks and how to verify their signatures.

Request
curl -X POST 'https://id-sa.payout.one/api/v1/verification/invitation' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
       "client_provided_iban": "CZ6508000000192000145399",
       "bank_account_requested": true,
       "callback_url": "https://example.com",
       "notify_url": "https://example.com/webhooks/payout-id"
     }'
Response 200
{
  "id": "f2a060df-4812-4335-8706-1c29e61c8b47",
  "redirect_url": "https://id-sa.payout.one/verifications/f2a060df-4812-4335-8706-1c29e61c8b47"
}

Request body

provided_emailstring<email>

Customer email, prefilled in the verification.

Max length 160 · Example [email protected]
provided_namestring

Customer first name, prefilled in the verification.

Example John
provided_surnamestring

Customer last name, prefilled in the verification.

Example Doe
bank_account_requestedboolean

Include the customer's bank account details in the webhook. Requires scope account_info.

Default false
aml_requestedboolean

Run an AML check on the customer. Requires scope aml and aml_notify_url.

Default false
client_provided_ibanstring

The IBAN the customer must verify, when you need that specific account rather than any account the customer can access. Must be a valid IBAN of a supported Slovak or Czech bank.

Example CZ6508000000192000145399
callback_url requiredstring

Where the customer is redirected after completing the verification steps.

Example https://example.com
notify_url requiredstring

Receives the webhook with the customer's details when all data are collected.

Example https://example.com/webhooks/payout-id
aml_notify_urlstring

Receives the webhook with the AML check results. Required when aml_requested is true.

Example https://example.com/webhooks/payout-id-aml

Response 200

idstring<uuid>

Invitation ID. Both webhooks carry it as data.id.

redirect_urlstring

Verification page to redirect the customer to.

Other responses

403

The access token is missing, invalid or expired, or lacks scope verify. The body is plain text, although the Content-Type header says application/json.

Example
UNAUTHORIZED: Missing or insuficient authorization
422

Validation failed. errors holds the messages by field, for example missing scope for condition when bank_account_requested or aml_requested is set without its scope.

Example
{
  "errors": {
    "client_provided_iban": [
      "invalid IBAN checksum"
    ]
  }
}

Was this page helpful?