Overview
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.
- Default selectors, hidden field mappings, and built-in copy keep checkout integration minimal.
Prerequisites
- Client ID and Client Secret for Finbility OAuth.
- A backend service that generates the checkout
token for the page.
- A checkout page served over HTTPS.
Base URL
Sandbox: https://test.openapi.finbility.io
OAuth 2.0
Get an access token before calling backend APIs
POST /v1/oauth/token?grant_type=client_credentials&scope=write,read
| 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"
}
Use the returned token as Authorization: Bearer <access_token> when calling payment and refund APIs.
Frontend
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 token delivery, locale, theme, callbacks, form action, and backend payload mapping.
- The default integration only needs one script tag, one mount div, and one submit button.
Real checkout pages only need one script tag and one mount div to get started. Hidden inputs are optional from the component perspective, but keeping them in markup is still a good way to make the submit payload easy to understand.
Quick Start
Minimal integration
- Include
finbility-card.js on the checkout page.
- Add a form with a single mount container and a submit button.
- Pass a backend-generated
token. The secure component renders cardholder name, card number, expiry, and CVC.
- Submit the form only after
controller.hasEncryptedPayload() is true.
<script src="/web/js/finbility-card.js"></script>
<form id="credit_card_form" action="/standard/credit_card" 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({
token: "BASE64_TOKEN_FROM_BACKEND",
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>
The component injects its own title, top helper text, secure card shell, loading state, and bottom error area. Merchants only need to provide the mount container.
Configuration
Token, hidden fields, and customization
The public integration entry point is token. Hidden inputs can be pre-rendered by the merchant form or created automatically by the component, and the rest of the checkout behavior can be customized through selectors, messages, theme, and callbacks.
{
"token": "BASE64_TOKEN_FROM_BACKEND"
}
Generate tokens on the backend. Do not hardcode permanent credential values into public sample pages or production templates.
| Option |
Type |
Description |
token |
string |
Backend-generated checkout token used to initialize the secure card component. |
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({
token: "BASE64_TOKEN_FROM_BACKEND",
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.js is 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.
Backend
Send the encrypted payload to the payment API
Your backend receives the form submission, maps the encrypted values to Finbility request fields, and calls the payment endpoint with your OAuth access token.
POST /v1/paymentDirect
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 |
order_id | Yes | Merchant order number, unique per payment attempt. |
payment_method | Yes | Payment method code, for example EECPB_3D. |
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 | Yes | Cardholder name. |
cardnum | Yes | Encrypted card number from cardNumber. |
cardexpiry | Yes | Concatenate month and year to MMYY format. |
cardcvv | Yes | Encrypted security code from cvNumber. |
source | Yes | Customer object described below. |
Only card number and CVC are encrypted by the frontend component. Expiry month and year remain plain text, so your backend should assemble cardexpiry from those two fields.
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": "EECPB_3D",
"request_type": "WEB",
"order_id": "100096247512",
"amount": "1.00",
"currency": "USD",
"description": "Product Title",
"website": "https://merchant.example",
"cardnum": "ev:encrypted:card-number",
"cardexpiry": "0926",
"cardcvv": "ev:encrypted:cvc",
"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"}
Payment Response
Response and query flow
The create-payment response and the payment query response share the same core structure.
GET /v1/payment/{payment_id}
| 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. |
{
"payment_id": "65df5a6791a211e583461c6f65f84b6d",
"transaction_id": "72c17f2d91a211e583461c6f65f84b6d",
"create_time": "2015-07-07T08:05:38Z",
"update_time": "2015-07-07T08:05:38Z",
"payment_method": "EECPB_3D",
"status": "SUCCESS",
"error_code": "",
"remarks": "",
"order_id": "100096247512",
"description": "Product Title",
"amount": "1.00",
"currency": "USD",
"request_type": "WEB",
"pay_url": "https://..."
}
Webhook
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. |
{
"transaction_id": "72c17f2d91a211e583461c6f65f84b6d",
"order_id": "100096247512",
"payment_id": "65df5a6791a211e583461c6f65f84b6d",
"payment_method": "EECPB_3D",
"error_message": "",
"status": "SUCCESS"
}
Refund
Refund by order id
POST /v1/refund/{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. |
description | No | Optional refund description. |
{
"amount": "1.00",
"currency": "USD",
"refund_order_id": "R20260414001",
"description": "Customer requested refund"
}
Refund query
GET /v1/refund/{refund_id}
The response returns the refund identifier, status, amount, currency, timestamps, and any failure reason.
Reference
Status and error handling
Typical payment statuses
- SUCCESS: payment completed.
- FAILED: payment could not be completed.
- PROCESSING: payment is still being processed.
- PENDING: payment is waiting for a downstream step or confirmation.
Integration checks
- Ensure the checkout page is served over HTTPS.
- Do not submit until the card controller reports an encrypted payload.
- Log webhook callbacks and reconcile them with payment query results.
- Handle token expiry and OAuth refresh on the backend.
If the card component enters an error state, block payment submission and surface a retry path. The built-in UI already exposes service-unavailable copy and a refresh action; the host page should respect that state instead of forcing form submission.