Integration model
Finbility provides a standard REST payment API plus a merchant-side secure card component. The frontend component is delivered through finbility-card.js, which wraps Evervault card fields behind a simpler integration surface.
- Frontend renders one secure card block and writes encrypted values into your form.
- Backend uses OAuth 2.0, then calls payment, query, webhook, and refund APIs.
- Apple Pay and Google Pay use the
/v1/paymentCollectAPI only; redirect the customer topay_urlto complete payment on the Finbility-hosted checkout page, which uses the Evervault JS SDK to render the wallet UI and encrypt payment data in the browser. - Default selectors, hidden field mappings, and built-in copy keep checkout integration minimal.
Prerequisites
- Client ID and Client Secret for Finbility OAuth.
- A checkout page served over HTTPS.
Base URL
Get your Client ID and Client Secret
API credentials are managed in the merchant dashboard under Settings > My profile > API Key.
- Use the displayed Client ID together with the Client Secret returned when the key is first generated or reset.
- The dashboard only shows a masked secret after creation. Save the full Client Secret immediately because it is only displayed once.
- If the secret is lost or needs to be rotated, reset the API Key in the dashboard and update your backend configuration before requesting new OAuth tokens.
clientSecret in browser code, public pages, or mobile app bundles.
Get an access token before calling backend APIs
| Header | Required | Description |
|---|---|---|
Authorization |
Yes | Basic + Base64(clientId:clientSecret) |
Accept |
Yes | application/json |
Content-Type |
Yes | application/x-www-form-urlencoded |
{
"access_token": "653633b2-8287-47b6-a7e4-40ec252fe9a8",
"token_type": "bearer",
"expires_in": 43035,
"scope": "write,read"
}
Authorization: Bearer <access_token> when calling payment and refund APIs.
Use finbility-card.js as the merchant integration layer
The script automatically loads the Evervault browser SDK, generates the secure card UI inside your mount element, manages loading and error states, enables the submit button when the encrypted payload is ready, and writes values into hidden inputs.
- The component handles secure fields, default copy, loading state, and hidden field updates.
- You control locale, theme, callbacks, form action, and backend payload mapping.
- The default integration only needs one script tag, one mount div, and one submit button.
Minimal integration
- Include
finbility-card.json the checkout page. - Add a form with a single mount container and a submit button.
- Initialize
FinbilityPayCard. The secure component renders cardholder name, card number, expiry, and CVC. - Submit the form only after
controller.hasEncryptedPayload()is true.
Environment script URLs
Use the matching script URL for each environment.
| Environment | Script URL |
|---|---|
| Test | https://test.payment.finbility.io/web/js/finbility-card.js |
| Production | https://payment.finbility.io/web/js/finbility-card.js |
https://test.payment.finbility.io with https://payment.finbility.io.
<script src="https://test.payment.finbility.io/web/js/finbility-card.js"></script>
<form id="credit_card_form" action="<YOUR_BACKEND_PAYMENT_ENDPOINT>" method="post" novalidate>
<div id="finbility-pay-card"></div>
<input type="hidden" name="cardholderName" id="finbility-pay-holder">
<input type="hidden" name="cardNumber" id="finbility-pay-card-number">
<input type="hidden" name="expirationMonth" id="finbility-pay-expiration-month">
<input type="hidden" name="expirationYear" id="finbility-pay-expiration-year">
<input type="hidden" name="cvNumber" id="finbility-pay-cv-number">
<button type="submit" id="js-pay-btn" disabled="disabled">Pay</button>
</form>
<script>
var controller = window.FinbilityPayCard.create({
locale: "en_US"
});
document.getElementById("credit_card_form").addEventListener("submit", function (event) {
event.preventDefault();
if (!controller || controller.isFailed()) {
return;
}
if (!controller.hasEncryptedPayload()) {
return;
}
this.submit();
});
</script>
Configuration and customization
Hidden inputs can be pre-rendered by the merchant form or created automatically by the component. Locale, theme, callbacks, and selectors can be customized without changing the integration model.
window.FinbilityPayCard.create({
locale: "en_US"
});
| Option | Type | Description |
|---|---|---|
locale |
string | Built-in locales: en_US and zh_CN. |
selectors |
object | Override mount, form, and submitButton. |
hiddenFields |
object | Override hidden field ids and names. Supported keys include holder, number, expiryMonth, expiryYear, and cvc. |
messages |
object | Override default field labels, placeholders, hints, and status copy. |
theme |
object | Override colors, radius, and text sizes without changing the integration model. |
cardOptions |
object | Pass supported Evervault card options such as field set or color scheme. |
onReady, onError, onChange, onStateChange |
function | Lifecycle callbacks for host page control and analytics. |
Example with custom selectors and hidden field ids
window.FinbilityPayCard.create({
locale: "zh_CN",
selectors: {
mount: "#custom-pay-card",
form: "#custom-form",
submitButton: "#submit-btn"
},
hiddenFields: {
holder: { id: "encryptedHolder", name: "cardholderName" },
number: { id: "encryptedCardNumber", name: "cardNumber" },
expiryMonth: { id: "encryptedMonth", name: "expirationMonth" },
expiryYear: { id: "encryptedYear", name: "expirationYear" },
cvc: { id: "encryptedCvc", name: "cvNumber" }
}
});
Browser expectations
finbility-card.jsis implemented in ES5 style for broad browser compatibility.- Target current versions of Chrome, Edge, Safari, and Firefox for merchant checkout pages.
- The script loads the Evervault browser SDK internally, so merchants only need to include one JS file.
Card payment: send the encrypted payload to the payment API
Your backend receives the form submission, maps the encrypted values to Finbility request fields, and calls /v1/paymentDirect with your OAuth access token. Wallet payments (Apple Pay, Google Pay) use /v1/paymentCollect instead.
Request headers
| Header | Required | Description |
|---|---|---|
Authorization |
Yes | Bearer <access_token> |
Accept |
Yes | application/json |
Content-Type |
Yes | application/json |
Core request fields
| Parameter | Required | Description |
|---|---|---|
channel_merchant_id | No | Unique ID assigned by the upstream provider |
order_id | Yes | Merchant order number, unique per payment attempt. |
payment_method | Yes | Payment method code: FINBI, FINBI_3D, or FINBI_TN. |
amount | Yes | Transaction amount with two decimals. |
currency | Yes | ISO currency code, for example USD or EUR. |
request_type | Yes | Request source, for example WEB, WAP, or SDK. |
description | Yes | Order description. Avoid /, =, and &. |
return_url | Yes | Redirect URL after payment completion. |
notify_url | Yes | Webhook URL for payment result notifications. |
website | Yes | Merchant website URL. |
cardholder | Conditional | Required for FINBI and FINBI_3D. Not used for FINBI_TN. |
cardnum | Conditional | Required for FINBI and FINBI_3D. Not used for FINBI_TN. |
cardmonth | Conditional | Required for FINBI and FINBI_3D. Not used for FINBI_TN. |
cardyear | Conditional | Required for FINBI and FINBI_3D. Not used for FINBI_TN. |
cardcvv | Conditional | Required for FINBI and FINBI_3D. Not used for FINBI_TN. |
token_id | Conditional | Required for FINBI_TN (MIT payment). Optional for FINBI_3D — pass INIT to register a token for future use. |
source | Yes | Customer object described below. |
expirationMonth and expirationYear from the form to cardmonth and cardyear.
Token-based payment (FINBI_TN)
FINBI_TN enables merchant-initiated recurring payments without cardholder interaction. The flow is:
- INIT — Complete a standard
FINBI_3Dpayment withtoken_id=INITin the request. The response includes atoken_idvalue (the outPaymentId from the gateway). - MIT — For subsequent charges, call
POST /v1/paymentDirectwithpayment_method=FINBI_TNand thetoken_idfrom Step 1. No card fields, no 3DS, no customer redirect.
payment_method=FINBI_3D with token_id=INIT for the initial transaction. The token_id returned in the response is the gateway transaction ID, which you store and reuse for all subsequent MIT payments.
Example: INIT (register token with FINBI_3D)
{
"return_url": "https://merchant.example/return",
"notify_url": "https://merchant.example/notify",
"payment_method": "FINBI_3D",
"request_type": "WEB",
"order_id": "100096247512",
"amount": "1.00",
"currency": "USD",
"description": "Product Title",
"website": "https://merchant.example",
"token_id": "INIT",
"cardnum": "ev:encrypted:card-number",
"cardmonth": "09",
"cardyear": "2026",
"cardcvv": "ev:encrypted:cvc",
"cardholder": "Chris Ma",
"source": {
"first_name": "Chris",
"middle_name": "",
"last_name": "Ma",
"country": "US",
"state": "CA",
"city": "Los Angeles",
"zip": "90001",
"email": "test@example.com",
"phone": "1-555-0100",
"address1": "100 Main Street",
"address2": "Suite 18",
"client_ip": "203.0.113.10",
"cpf": ""
}
}
Example: MIT (FINBI_TN with token)
{
"return_url": "https://merchant.example/return",
"notify_url": "https://merchant.example/notify",
"payment_method": "FINBI_TN",
"request_type": "WEB",
"order_id": "100096247515",
"amount": "1.00",
"currency": "USD",
"description": "Product Title",
"website": "https://merchant.example",
"token_id": "80780000",
"source": {
"first_name": "Chris",
"middle_name": "",
"last_name": "Ma",
"country": "US",
"state": "CA",
"city": "Los Angeles",
"zip": "90001",
"email": "test@example.com",
"phone": "1-555-0100",
"address1": "100 Main Street",
"address2": "Suite 18",
"client_ip": "203.0.113.10"
}
}
Customer source fields
| Parameter | Required | Description |
|---|---|---|
client_ip | Yes | Customer IP address. |
first_name | Yes | Customer first name. |
middle_name | No | Customer middle name. |
last_name | Yes | Customer last name. |
country | Yes | ISO country code, for example US or CN. |
state | Conditional | Required for US and CA card payments. |
city | Yes | City name. |
zip | Conditional | Required for US and CA card payments. |
email | Yes | Customer email address. |
address1 | Yes | Primary address line. |
address2 | No | Secondary address line. |
phone | Yes | Phone number. |
cpf | No | Brazilian tax ID when required by method or region. |
{
"return_url": "https://merchant.example/return",
"notify_url": "https://merchant.example/notify",
"payment_method": "FINBI_3D",
"request_type": "WEB",
"order_id": "100096247512",
"amount": "1.00",
"currency": "USD",
"description": "Product Title",
"website": "https://merchant.example",
"cardnum": "ev:encrypted:card-number",
"cardmonth": "09",
"cardyear": "2026",
"cardcvv": "ev:encrypted:cvc",
"cardholder": "Chris Ma",
"source": {
"first_name": "Chris",
"middle_name": "",
"last_name": "Ma",
"country": "US",
"state": "CA",
"city": "Los Angeles",
"zip": "90001",
"email": "test@example.com",
"phone": "1-555-0100",
"address1": "100 Main Street",
"address2": "Suite 18",
"client_ip": "203.0.113.10",
"cpf": ""
}
}
3DS browser header
BrowserInfo: {"acceptHeader":"application/json","language":"en","userAgent":"Mozilla/5.0","javaEnabled":"true","colorDepth":"24","screenHeight":"1080","screenWidth":"1920","timeZoneOffset":"-480"}
/v1/paymentDirect. Apple Pay and Google Pay must use /v1/paymentCollect instead. See the wallet section below.
Apple Pay and Google Pay
Apple Pay and Google Pay are server-side collect flows. Your backend calls /v1/paymentCollect with the wallet payment method code, then redirects the customer to the pay_url returned in the API response. The pay_url points to a Finbility-hosted checkout page that uses the Evervault JS SDK to render the Apple Pay or Google Pay button and encrypt payment data in the browser — the same security model as finbility-card.js for card payments. The customer authorizes payment in the native wallet UI; Finbility notifies your notify_url and redirects to return_url when finished.
These methods do not use finbility-card.js and do not accept card fields. Request parameters match the card payment API except for the endpoint, payment_method, and the absence of card-related fields.
Checkout page security
The wallet checkout page loads the Evervault browser SDK (js.evervault.com/v2) and uses evervault.ui.applePay() or evervault.ui.googlePay() to mount the wallet button. When the customer authorizes payment:
- The Evervault SDK captures the encrypted payment token from Apple Pay or Google Pay.
- The encrypted payload is submitted via
fetchto a Finbility backend endpoint for processing. - The backend decrypts the payload through Evervault Relay and forwards it to the upstream payment provider.
- The result is returned to the checkout page: success, 3DS challenge, or failure.
Payment method codes
payment_method |
Method | Endpoint |
|---|---|---|
FINBI_AP | Apple Pay | POST /v1/paymentCollect |
FINBI_GP | Google Pay |
Integration flow
- Obtain an OAuth access token (same as other backend APIs).
- POST order and customer details to
/v1/paymentCollectwithFINBI_APorFINBI_GP. - Read
pay_urlfrom the response and redirect the customer (HTTP 302 or client-sidewindow.location). - The customer lands on the Finbility-hosted checkout page, which loads the Evervault SDK and renders the wallet button.
- The customer taps the Apple Pay or Google Pay button and authorizes payment in the native wallet UI.
- The Evervault SDK encrypts the payment token and submits it to Finbility for processing.
- If 3D Secure is required, the customer completes the 3DS challenge; otherwise the payment is finalized.
- Receive the final result on
notify_urland reconcile withGET /v1/payment/{payment_id}if needed.
Request headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <access_token> |
Accept | Yes | application/json |
Content-Type | Yes | application/json |
Core request fields
Same fields as the card payment API, except card fields and the 3DS BrowserInfo header are not used.
| Parameter | Required | Description |
|---|---|---|
channel_merchant_id | No | Unique ID assigned by the upstream provider. |
order_id | Yes | Merchant order number, unique per payment attempt. |
payment_method | Yes | FINBI_AP for Apple Pay or FINBI_GP for Google Pay. |
amount | Yes | Transaction amount with two decimals. |
currency | Yes | ISO currency code, for example USD or EUR. |
request_type | Yes | Request source, for example WEB, WAP, or SDK. |
description | Yes | Order description. Avoid /, =, and &. |
return_url | Yes | Redirect URL after payment completion. |
notify_url | Yes | Webhook URL for payment result notifications. |
website | Yes | Merchant website URL. |
source | Yes | Customer object (same structure as card payments). |
cardholder, cardnum, cardmonth, cardyear, or cardcvv for wallet payments. Calling /v1/paymentDirect with FINBI_AP or FINBI_GP is rejected by the API.
Example: Apple Pay
{
"return_url": "https://merchant.example/return",
"notify_url": "https://merchant.example/notify",
"payment_method": "FINBI_AP",
"request_type": "WEB",
"order_id": "100096247513",
"amount": "1.00",
"currency": "USD",
"description": "Product Title",
"website": "https://merchant.example",
"source": {
"first_name": "Chris",
"middle_name": "",
"last_name": "Ma",
"country": "US",
"state": "CA",
"city": "Los Angeles",
"zip": "90001",
"email": "test@example.com",
"phone": "1-555-0100",
"address1": "100 Main Street",
"address2": "Suite 18",
"client_ip": "203.0.113.10"
}
}
Example: Google Pay
{
"return_url": "https://merchant.example/return",
"notify_url": "https://merchant.example/notify",
"payment_method": "FINBI_GP",
"request_type": "WEB",
"order_id": "100096247514",
"amount": "1.00",
"currency": "EUR",
"description": "Product Title",
"website": "https://merchant.example",
"source": {
"first_name": "Chris",
"last_name": "Ma",
"country": "DE",
"city": "Berlin",
"zip": "10115",
"email": "test@example.com",
"phone": "+49-30-1234567",
"address1": "Example Street 1",
"client_ip": "203.0.113.10"
}
}
Response after create payment
When the payment is created successfully and a wallet step is required, the response includes pay_url with status RedirectApple or RedirectGoogle. Redirect the customer to pay_url to enter the Apple Pay or Google Pay flow. Query and webhook behavior are the same as for card payments.
{
"payment_id": "65df5a6791a211e583461c6f65f84b6d",
"transaction_id": "72c17f2d91a211e583461c6f65f84b6d",
"payment_method": "FINBI_AP",
"status": "RedirectApple",
"pay_url": "https://payment.finbility.io/payments/65df5a6791a211e583461c6f65f84b6d/checkout",
"order_id": "100096247513",
"amount": "1.00",
"currency": "USD"
}
window.location.href = response.pay_url (web) or an HTTP 302 from your server. After payment processing completes, the checkout page redirects the customer to your return_url and posts the result to notify_url.
Response and query flow
The create-payment response and the payment query response share the same core structure.
| Field | Description |
|---|---|
payment_id | Finbility payment identifier. |
transaction_id | Platform transaction identifier. |
status | Current payment status. |
error_code | Error code when a payment does not succeed. |
remarks | Human-readable failure reason. |
pay_url | Redirect URL when the method requires an external step. For FINBI_AP and FINBI_GP, the status is RedirectApple or RedirectGoogle; redirect the customer to this URL to complete payment on the Finbility-hosted Evervault checkout page. |
token_id | Token for subsequent FINBI_TN (MIT) payments. Returned when the original FINBI_3D payment succeeds with token_id=INIT. |
{
"payment_id": "65df5a6791a211e583461c6f65f84b6d",
"transaction_id": "72c17f2d91a211e583461c6f65f84b6d",
"create_time": "2015-07-07T08:05:38Z",
"update_time": "2015-07-07T08:05:38Z",
"payment_method": "FINBI",
"status": "SUCCESS",
"error_code": "",
"remarks": "",
"order_id": "100096247512",
"description": "Product Title",
"amount": "1.00",
"currency": "USD",
"request_type": "WEB",
"pay_url": "https://...",
"token_id": "80780000"
}
Payment result notification
Finbility sends a POST request to your notify_url when the payment result is available.
| Field | Description |
|---|---|
transaction_id | Platform transaction identifier. |
order_id | Merchant order number. |
payment_id | Finbility payment identifier. |
payment_method | Payment method code. |
error_message | Failure reason, empty on success. |
status | Current transaction status. Common values: SUCCESS / FAIL. |
{
"transaction_id": "72c17f2d91a211e583461c6f65f84b6d",
"order_id": "100096247512",
"payment_id": "65df5a6791a211e583461c6f65f84b6d",
"payment_method": "FINBI_3D",
"error_message": "",
"status": "SUCCESS"
}
Notify URL response
Return HTTP status 200 on receipt. No response body is required.
Notification retry schedule
If the notification fails or a 200 is not returned, the platform retries at the following intervals: 2 min, 10 min, 10 min, 60 min, 120 min (5 retries total).
Notification signature verification
Notifications do not require signature verification. The recommended approach is to call the query API (GET /v1/payment/{payment_id}) after receiving a notification to confirm the final status. The query API requires OAuth 2.0 authentication. This is recommended because notifications may be delayed or lost.
Refund by order id
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <access_token> |
Accept | Yes | application/json |
Content-Type | Yes | application/json |
Refund request body
| Parameter | Required | Description |
|---|---|---|
amount | Yes | Refund amount. |
currency | Yes | Currency code. |
refund_order_id | Yes | Merchant refund order number, unique per refund. |
notify_url | Yes | Webhook URL for refund result notifications. |
description | No | Optional refund description. |
{
"amount": "1.00",
"currency": "USD",
"refund_order_id": "R20260414001",
"notify_url": "https://merchant.example/notify",
"description": "Customer requested refund"
}
Refund response
| Parameter | Max Length | Required | Description |
|---|---|---|---|
refund_id | 50 | Yes | Platform refund ID. |
refund_order_id | 50 | Yes | Merchant refund order number. |
order_id | 50 | Yes | Merchant payment order ID. |
amount | 13,2 | Yes | Refund amount, two decimal places. |
currency | 3 | Yes | Currency code, e.g. CNY, USD, EUR. |
notify_url | 255 | Yes | Webhook URL for refund result notifications. |
status | 50 | Yes | Refund status: SUCCESS (completed), FAIL (failed), WAIT (pending). |
create_time | - | Yes | Creation time. |
update_time | - | Yes | Last update time. |
links | - | Yes | Operation links (e.g. self query). |
{
"refund_id": "2c04080b91a211e583461c6f65f84b6d",
"create_time": "2015-07-07T09:10:52Z",
"update_time": "2015-07-07T09:10:52Z",
"amount": "1.00",
"currency": "CNY",
"order_id": "db9e9e6b-918e-11e5-8346-1c6f65f84b6d",
"refund_order_id": "e8578eb-91a0-11e5-8346-1c6f65f84b6d",
"links": [
{
"href": "http://.xxx.com/v1/refund/2c04080b91a211e583461c6f65f84b6d",
"rel": "self",
"method": "GET"
}
],
"status": "WAIT",
"notify_url": "http://www.mysite.com/refund_notify_url"
}
Refund query
Query a refund by its platform refund ID. The response uses the same structure as the refund response above.
Test cards
Use the following values in the test environment (https://test.openapi.finbility.io). Do not use them in production.
Pure API integration (encrypted payloads)
For backend-only testing with POST /v1/paymentDirect, send the pre-encrypted sandbox values below. Map them to cardnum and cardcvv; set cardmonth to 12 and cardyear to 2027.
| API field | Test value |
|---|---|
cardnum |
ev:QkTC:uFPwr6En2GjHgYsG:AmxayDxmzMrpYZrFEws9oXFpoZ2/zZ8U/JqPK//KHs1D:2ji+ErydhhW/CPlDPQDmYAsHkOrTaJI5sNfGCTYjupgeVMPQ0zsTlOUppQ8bcAs:$ |
cardcvv |
ev:QkTC:5zat9SYrUnXlQogT:AmxayDxmzMrpYZrFEws9oXFpoZ2/zZ8U/JqPK//KHs1D:ix/L7iCeAxYk5xaV7lwpxRXAZgGbq7ge3RX8DfV6p0tffQ:$ |
cardmonth |
12 |
cardyear |
2027 |
Checkout UI integration (plain text)
For testing with finbility-card.js on the hosted checkout page or the demo page, enter these values in the secure card form. The component encrypts card number and CVC before submit.
| Field | Test value |
|---|---|
| Card number | 4149011500000147 |
| CVC | 123 |
| Expiry | 12/27 (1227 in MMYY) |
Status and error handling
Typical payment statuses
- SUCCESS: payment completed.
- FAIL: payment could not be completed.
- PROCESSING: payment is still being processed.
- PENDING: payment is waiting for a downstream step or confirmation (e.g. before wallet redirect).
- Redirect3DS: 3D authentication required. Redirect the customer to
pay_urlto complete authentication. - UNCAPTURE: Awaiting capture — not currently used.
Wallet payment methods
FINBI_AP— Apple Pay (POST /v1/paymentCollect)FINBI_GP— Google Pay (POST /v1/paymentCollect)
Token payment method
FINBI_TN— Token-based MIT (Merchant Initiated Transaction). UsePOST /v1/paymentDirectwithtoken_idinstead of card fields. No customer interaction required.
Integration checks
- Ensure the checkout page is served over HTTPS.
- Do not submit until the card controller reports an encrypted payload.
- For wallet payments, redirect to
pay_urlafter create payment. - Log webhook callbacks and reconcile them with payment query results.
- Handle token expiry and OAuth refresh on the backend.