🧠Progression Guide
Overview
This guide describes the recommended path for integrating FinqLink (Pay) and FinqData (AIS), from the first request with shared test credentials to live production traffic. Each stage validates one part of the setup before moving to the next.
For a shorter introduction to the first request, see the Quick Start page.
Integration stages
1. Shared sandbox API client | The API flow, using shared test credentials and sandbox bank methods |
2. Dedicated sandbox client with stage methods | Real bank flows under limits, using your own sandbox API client |
3. OAuth2 on | The production authentication model, still on the sandbox environment |
4. Go live | Production base URL, production methods and production key |
Environments
The integration involves two separate environment settings:
- Finqware environment: the host that receives your requests. Use
sandbox-link.finqware.comfor integration and testing, with both sandbox and stage methods, andlink.finqware.comfor live production traffic. - Bank method environment: the
envvalue sent inais_methodorpayment_method. It can besandbox,stageorprod.
The values used in each stage:
1 |
|
2 |
|
3 |
|
4 |
|
Stage 1: Shared sandbox API client
Finqware provides a shared test client_id and client_secret for the /api/test endpoints.
With env set to sandbox, requests are routed to the sandbox APIs exposed by the banks. The selection of providers is limited, and bank sandbox APIs return static test data. Use this stage to understand the flow, then move to Stage 2 once one end-to-end flow is completed.
Create a consent link (FinqData)
Creates an AIS consent and returns a web_url to be sent to the end user.
curl -X POST https://sandbox-link.finqware.com/api/test/ais/consents/create \
-H "Content-Type: application/json" \
-d '{
"client_id": "{{client_id}}",
"client_secret": "{{client_secret}}",
"ais_method": {
"provider_id": [],
"country": ["ro"],
"account_owner_type": ["retail", "corporate"],
"interface": ["psd2_api"],
"env": "sandbox"
},
"consent": {
"scope": ["accounts", "balances", "transactions"],
"consent_validity_days": 3
},
"options": {
"type": "link",
"expires_in": 1440,
"webhook_url": "https://example.com/webhooks",
"back_to_app_url": "https://example.com/success",
"back_from_error_url": "https://example.com/error",
"ux_locale": "ro",
"ux_template": "default"
},
"tracking": {
"user_tracking_id": "user-550e8400-e29b-41d4-a716-446655440000",
"org_tracking_id": "department-accounting"
}
}'
Response:
{
"api_client_app": "<<api_client_app_name>>",
"consent_id": "8f3a2b1c-9d4e-4a7b-b218-55e6c7d89f01",
"consent_validity_days": 3,
"created_at": "2026-04-22T08:42:15.301284Z",
"expires_at": "2026-04-25T08:42:15.289117Z",
"request_id": "2c1f9d47-bb8e-4312-90a5-7e4d6f1b2a83",
"web_id": "BKFq7m2vNPxZtUcLqRYsWdHfKp5aDx_gJ8hV3oNcEwRYLBa2_jPQxK9bNt3Gz",
"web_url": "https://sandbox-pay.finqware.com/web/test/ais/BKFq7m2vNPxZtUcLqRYsWdHfKp5aDx_gJ8hV3oNcEwRYLBa2_jPQxK9bNt3Gz"
}
Store consent_id (used in API calls), web_id (used for support correlation) and request_id (used for debugging). Redirect the end user to web_url.
Create a payment link (FinqLink)
Creates a payment link and returns a web_url to be sent to the end user.
curl -X POST https://sandbox-link.finqware.com/api/test/links/create \
-H "Content-Type: application/json" \
-d '{
"client_id": "{{client_id}}",
"client_secret": "{{client_secret}}",
"single_transfer": {
"amount": {
"value": "1",
"currency": "ron"
},
"creditor": [
{
"provider_id": "ing_ro",
"account_identification": {
"iban": "RO97INGB0000999910924372"
},
"creditor_info": {
"name": "Beneficiary Name",
"country": "RO",
"town": "Bucharest",
"postcode": "1051",
"address": "Test Street 1"
}
}
],
"remittance_info": {
"unstructured": "Payment for Order 12345",
"structured": {}
},
"fee_bearer": "SHA",
"transfer_id": {
"end_to_end_id": "E2E-REF-12345",
"instruction_id": "INSTR-12345"
}
},
"payment_method": {
"provider_id": [],
"country": ["ro"],
"remitter_type": ["retail"],
"payment_scheme": ["ro_domestic"],
"interface": ["psd2_api"],
"env": "sandbox"
},
"options": {
"expires_in": 1440,
"webhook_url": "https://example.com/payment/webhooks",
"back_to_app_url": "https://example.com/payment/success",
"back_from_error_url": "https://example.com/payment/failed",
"back_url_with_status": true,
"allow_reset_on_fail": true,
"max_resets_on_fail": 3,
"auto_cancel_on_reload": true,
"type": "link",
"open_authz_page": "new_tab",
"ux_locale": "en",
"ux_template": "default",
"user_agent": "mobile",
"user_editable": ["remitter_type"]
}
}'
Response:
{
"api_client_app": "<<api_client_app_name>>",
"created_at": "2026-04-22T10:05:48.472019Z",
"expires_at": "2026-04-23T10:05:48.318772Z",
"link_id": "3e8d6a1f-7c42-4bd9-a015-d6ef2b94ac78",
"request_id": "a1b7c3d4-5e6f-4078-9a2b-1c3d4e5f6a7b",
"web_id": "CMRn9p4wYQvZuKdNxSZtXeIgLq6bEx_hKp9zW4pOdFxSMCb3_kQRyL0cOu4Ha",
"web_url": "https://sandbox-pay.finqware.com/web/test/links/CMRn9p4wYQvZuKdNxSZtXeIgLq6bEx_hKp9zW4pOdFxSMCb3_kQRyL0cOu4Ha"
}
Store link_id (used in API calls), web_id (used for support correlation) and request_id (used for debugging). Redirect the end user to web_url.
Sandbox test credentials
The sandbox test credentials for each provider (PSU IDs, usernames, IBANs, SMS codes) are listed in the Sandbox testing section of the Quick Start page.
Available providers and methods
The /providers/list endpoint returns the providers and methods enabled for your API client. The results can be filtered by environment, payment scheme, interface and remitter or account owner type.
curl -X POST https://sandbox-link.finqware.com/api/test/providers/list \
-H "Content-Type: application/json" \
-d '{
"client_id": "{{client_id}}",
"client_secret": "{{client_secret}}",
"options": {
"show_payment_methods": true,
"show_validation_schema": true,
"payment_methods_filter": {
"remitter_type": ["retail"],
"payment_scheme": ["ro_domestic"],
"interface_type": ["psd2_api"],
"interface_env": "sandbox"
},
"show_ais_methods": false,
"ais_methods_filter": {
"account_owner_type": ["retail"],
"interface_type": ["psd2_api"],
"interface_env": "sandbox"
}
}
}'
show_payment_methodsandshow_ais_methodsselect which methods are included in the responsepayment_methods_filterandais_methods_filterrestrict the returned methods, including byinterface_env(sandbox,stageorprod)
The same information is available in the public dashboard.
Checklist
- Requests authenticate with the test
client_idandclient_secret - At least one consent link or payment link is created
- A sandbox WebUI flow is completed by opening
web_url
Stage 2: Dedicated sandbox client with stage methods
Request a dedicated sandbox API client from Finqware. You will receive your own client_id and client_secret.
The base URL and the /api/test path remain the same. The method env changes from sandbox to stage, which routes requests to the production APIs of the banks, under the limits listed below.
Note: stage is not a separate Finqware environment. It is the value sent in ais_method.env or payment_method.env.
Limits
- Maximum payment amount:
5.00(Pay) - Maximum consent validity:
3days (Data)
Changes from Stage 1
Only the env value changes:
{
"ais_method": {
"provider_id": ["{{provider_id}}"],
"country": ["ro"],
"interface": ["psd2_api"],
"env": "stage"
}
}
What to test
FinqData:
- Create a consent link with stage methods
- Complete the authorization flow at the bank
- Wait for the consent status to become
active - Call
/ais/accounts/list,/ais/balances/listand/ais/transactions/list, including pagination - Trigger an on-demand data refresh with
/ais/jobs/create
FinqLink:
- Create a low-value payment link
- Complete the payment authorization flow
- Retrieve the link with
/links/get - Validate webhook delivery and status reconciliation
- Validate the redirect behavior (
back_to_app_url,back_from_error_url,back_url_with_status)
On-demand data refresh jobs
Use /ais/jobs/create to fetch the latest accounts, balances and transactions from the bank for an active consent. To track completion, poll /ais/jobs/get or listen for the job_status_update webhook.
curl -X POST https://sandbox-link.finqware.com/api/test/ais/jobs/create \
-H "Content-Type: application/json" \
-d '{
"client_id": "{{client_id}}",
"client_secret": "{{client_secret}}",
"consent_id": "eba9a9f4-3cfb-4684-b118-97626674fbf9",
"callback_url": "https://example.com/webhook"
}'
- A job can take from a few seconds to a few minutes
- Only one job can run at a time for a consent
- After a successful job, a cooldown of 5 minutes applies before another job can be created, measured from the moment the previous job completed
- After a failed job, a new job can be created immediately
Webhooks
Finqware sends a webhook notification whenever a payment link, a consent or a data refresh job changes status. Webhooks are the recommended way to keep your backend in sync. Polling the corresponding get endpoints should only be used as a fallback.
payment_status_update | A payment link changed status (Pay) |
consent_status_update | An AIS consent changed status (Data) |
job_status_update | A data refresh job changed status (Data) |
Webhooks are signed with JWS and can be verified using the JWKS published at /.well-known/jwks.json. See Webhook signing and callbacks for the verification steps, the key rotation policy and the outbound IP addresses.
Checklist
- Requests use your dedicated client and stage methods, within the agreed limits
- The webhook endpoint is deployed and receives test events
- At least one Data or Pay flow is completed end to end with a real bank
Stage 3: OAuth2 on the sandbox environment
The host remains sandbox-link.finqware.com, and the authentication model changes. Requests move from /api/test to /api/v2, and from client_id and client_secret in the request body to an OAuth2 Authorization: Bearer header. This stage validates the production security model before moving to the production environment.
Generate a key pair
Use the generate_keys.sh script to create an RSA key pair for Private Key JWT. It produces three files:
private.key.pem: the private key, to be stored in a secret managerprivate.key.json: the private key in JWK format, with the same confidentiality requirementspublic.key.json: the public key in JWK format, to be shared with Finqware
Example of a public.key.json file:
{
"kty": "RSA",
"kid": "generated-key-id",
"n": "base64url-modulus",
"e": "AQAB",
"alg": "RS256",
"use": "sig"
}
What to send to Finqware
Send one of the following to support@finqware.com:
- The
public.key.jsonfile, attached or inline - The URL of a JWKS endpoint hosted under your own domain
Finqware registers the key, configures the OAuth2 API client and returns its client_id together with the token endpoint, audience and scope. This is typically the same client_id that will be used in production.
Note: With a JWKS URL, Finqware fetches the public key from your endpoint and key rotations are picked up automatically, without a new key exchange.
Get an access token
Sign a JWT with your private key and exchange it for an access token at the token endpoint. The full procedure is described in Getting an Access Token.
curl -X POST https://finqware.okta.com/oauth2/<auth_server_id>/v1/token \
-H "Accept: application/json" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "scope=pay_by_link" \
--data-urlencode "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
--data-urlencode "client_assertion=<signed_jwt>"
The response contains a short-lived access_token. Cache it and reuse it until it expires.
Call the /api/v2 endpoints
The endpoint paths (/ais/consents/create, /links/create etc.) are the same under /api/v2. The request body keeps client_id and no longer includes client_secret.
curl -X POST https://sandbox-link.finqware.com/api/v2/ais/consents/create \
-H "Authorization: Bearer {{access_token}}" \
-H "Content-Type: application/json" \
-d '{
"client_id": "{{oauth2_client_id}}",
"ais_method": {
"provider_id": ["{{provider_id}}"],
"env": "stage"
},
"consent": {
"scope": ["accounts", "balances", "transactions"],
"consent_validity_days": 3
},
"options": { "type": "link", "expires_in": 1440 }
}'
Note: The Bearer token authenticates the client, and the client_id in the request body identifies it. The two must refer to the same API client.
Checklist
- The private key is stored securely and the public key is registered by Finqware
- Access tokens are obtained using Private Key JWT
- Requests to
/api/v2are accepted with theAuthorization: Bearerheader - Stage methods behave as in Stage 2
Stage 4: Production
The base URL changes to link.finqware.com and the method env changes to prod. The authentication model, the request format and the webhook handling remain the same.
Your API client must be set up by Finqware in the production environment before live traffic can be sent. To start the transition, contact support@finqware.com and request production access.
Production uses a separate key:
- Generate a new key pair, as in Stage 3
- Include the production
public.key.jsonwhen contacting Finqware - In most cases the
client_idremains the same as in Stage 3, and only the key changes
Note: If you shared a JWKS URL in Stage 3, publish the production key at the same endpoint instead of sending a file. This is the recommended approach for production, as later key rotations do not require a new key exchange.
Production request
POST https://link.finqware.com/api/v2/ais/consents/create
Authorization: Bearer {{access_token}}
Content-Type: application/json
{
"client_id": "{{oauth2_client_id}}",
"ais_method": { "env": "prod", ... }
}
mTLS
OAuth2 is the only mandatory authentication mechanism in production. mTLS is supported as an optional, complementary security layer and is available on both the sandbox and the production base URL, so it can be configured and tested before going live. See mTLS for certificate onboarding and configuration.
Further reference
For the full request and response contract of each endpoint, see the Pay APIs and Data APIs reference. For any other questions, contact support@finqware.com.
On this page
- 🧠Progression Guide