You can use Bongloy accept online payments from your customers. Bongloy currently supports UnionPay credit, debit and prepaid cards. Integrating Bongloy into your app or website can begin as soon as you create a Bongloy Sandbox account, requiring only three steps:
In order to get started with the API, you'll need to get your API Keys. Your test API keys can be found in the developer section on the Bongloy Sandbox. There are two types of API keys: publishable and secret.
Bongloy's API is inspired by Stripe's REST API. Stripe is a US-based technology company which allows individuals and businesses to receive online payments. We thank Stripe for inspiring us to create a product which enables digital payments in Cambodia.
Where possible we try to make the Bongloy API compatible with Stripe's REST API. This makes integration easier because Stripe already has official libraries for different programming languages and mobile platforms. There's also bunch of pre-built extensions, platforms, and plugins to use Bongloy without needing to write any code.
We encourage you to use Stripe's official libraries, or third party libraries and plugins written for Stripe when connecting to Bongloy. This will ens ure that you receive the latest security updates and bug fixes.
Integrating a Stripe library or plugin with Bongloy varies according to the particular library. Below are some code snippits for some popular programming languages and platforms.
# Gemfile
gem "stripe", github: "stripe/stripe-ruby"
# config/initializers/bongloy.rb
Bongloy = Stripe
Bongloy.api_base = "https://api.bongloy.com"
$ composer require stripe/stripe-php
<?php
require_once('vendor/autoload.php');
use Stripe As Bongloy;
Bongloy\Stripe::$apiBase = "https://api.bongloy.com";
?>
To check that your integration is working correctly, make a test API request using your test secret key to create a charge. If the request is successful you should see the charge in your sandbox dashboard.
# bongloy_test.rb
# replace the API key in the following line with your secret API key
Bongloy.api_key = "sk_test_abcde..."
charge = Bongloy::Charge.create(
amount: 999,
currency: "usd",
source: "tok_union_pay"
)
<?php
// bongloy_test.php
// replace the API key in the following line with your secret API key
Bongloy\Stripe::setApiKey("sk_test_abcde...");
$charge = Bongloy\Charge::create([
"amount" => 999,
"currency" => "usd",
"source" => "tok_union_pay"
]);
?>
Anyone involved with the processing, transmission, or storage of card data must comply with the] Payment Card Industry Data Security Standards (PCI DSS). Bongloy has been audited by an independent PCI Qualified Security Assessor (QSA) and is certified as a PCI Level 1 Service Provider. This is the most stringent level of certification available in the payments industry.
PCI compliance is a shared responsibility and applies to both Bongloy and your business. When accepting payments, you must do so in a PCI compliant manner. The simplest way for you to be PCI compliant is to never see (or have access to) card data at all. Bongloy makes this easy for you as we can do the heavy lifting to protect your customers' card information. You can simplify your PCI compliance as long as you:
Bongloy.js makes it easy to collect credit card details without having the information touch your server. Bongloy.js gives you complete control over the UI and does not depend on JQuery. Use Bongloy.js if you want to accept payments on your website. If your building a mobile application then we recommend that you use Stripe's official libraries for iOS and Android.
Add the following script tag to your page to get started with Bongloy.js:
<script type="text/javascript" src="https://js.bongloy.com/v3"></script>
You must set your publishable key with setPublishableKey
before using Bongloy.js to identify your website when communicating with Bongloy.
Remember to replace the test key with your live key in production.
You can get all your keys from the developer section of the
dashboard.
setPublishableKey
also accepts an optional options
object
where you can specify a bongloyAccount
, a connected account ID in which
to perform actions on.
Use this option when using
Bongloy Connect
to create tokens on behalf of another account. Note that when passing a
bongloyAccount
, you still use the publishable key of the
platform application account, not that of the connected account.
Bongloy.setPublishableKey('pk_test_abcde...');
// Note: We could also get our Bongloy Publishable Key
// from a meta tag attribute in the HTML head. E.g.
// var publishableKey = document.head.querySelector("meta[name=bongloy-publishable-key]").content;
// Bongloy.setPublishableKey(publishableKey);
//
// When using Connect, you can set the bongloyAccount header to specify the
// connected account in which to perform actions on behalf of. For example:
// Bongloy.setPublishableKey('pk_test_abcde...', { bongloyAccount: "connected-account-id" });
Bongloy.createToken
createToken
converts sensitive card data to a single-use
token which you can safely pass to your server to charge the user.
var cardObject = {
// The HTML in this example uses `data-name` attribute
// instead of the HTML name attribute to prevent
// sending credit card information fields to the backend server via HTTP POST
number: document.querySelector('[data-name="cardNumber"]').value,
exp_month: document.querySelector('[data-name="expMonth"]').value,
exp_year: document.querySelector('[data-name="expYear"]').value,
cvc: document.querySelector('[data-name="cvc"]').value
}
Bongloy.createToken('card', cardObject, bongloyResponseHandler);
The first argument to Bongloy.createToken
is the type of token
you want to create. For now this the value must be card
.
The second argument to is a JavaScript object containing credit card data entered by the user. It should contain the following required fields:
number
'4242424242424242'
exp_month
1
exp_year
2023
cvc
'123'
The following fields are entirely optional. They cannot result in a token creation failing:
name
The third argument bongloyResponseHandler
is a callback you provide
to handle the response from Bongloy. It should do the following:
Here's a sample implementation of bongloyResponseHandler
:
function bongloyResponseHandler(status, response) {
// hide error messages
var errorMessages = document.querySelector('[data-name="errorMessages"]');
errorMessages.classList.add('hidden');
if (statusCode === 201) {
// On success, set token in your checkout form
document.querySelector('[data-name="cardToken"]').value = response.id;
// Then, submit the form
checkoutForm.submit();
}
else {
// If unsuccessful, display an error message.
// Note that `response.error.message` contains a preformatted error message.
document.querySelector("input[type=submit]").removeAttribute('disabled');
errorMessages.classList.remove('hidden');
errorMessages.innerHTML = response.error.message;
}
}
response
is of the following form:
{
"id": "af2a6c7c-11f4-4db1-bff6-ee991ebb41f1",
"object": "token",
"created": 1535543720,
"livemode": false,
"card": {
"id": "b4199585-dc1c-4e06-9fdd-4261d703c6a1",
"object": "card",
"created": 1535543720,
"livemode": false,
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": "unchecked",
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "visa",
"country": null,
"customer": null,
"cvc_check": "pass",
"exp_month": 8,
"exp_year": 2020,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"last4": "4242",
"name": null
},
"client_ip": "96.9.66.131",
"type": "card",
"used": false
}
createToken
is an asynchronous call. It returns immediately and invokes bongloyResponseHandler
when it receives a response from Bongloy's servers.
Bongloy.js doesn't validate credit card data before sending it to the API. But if the card isn't valid the API will send you a message in the response containing the errors. If you need client side validation you can use something like jessepollak/payment.
Stripe has native libraries for Android and iOS which let you collect credit card information without having to deal with sensitive data passing through your servers. Stripe's Mobile Libraries are compatible with Bongloy. Below are some code snippits to get Stripe's Mobile Libraries working with Bongloy.
Here's an example of how to configure Stripe iOS with Bongloy and CocoaPods.
# Podfile
pod "Stripe"
$ pod install
Don't forget to use the .xcworkspace
file to open your project in Xcode, instead of the .xcodeproj
file, from here on out.
To update to the latest version of the SDK, simply run:
$ pod update Stripe
// AppDelegate.swift
import UIKit
import Stripe
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
STPPaymentConfiguration.shared().publishableKey = "pk_test_abcde..."
// do any other necessary launch configuration
return true
}
}
// BongloyAPIClient.h
#import <Stripe/Stripe.h>
@interface BongloyAPIClient : STPAPIClient
@property (nonatomic, strong, readwrite) NSURL *apiURL;
@property (nonatomic, strong, readonly) NSURLSession *urlSession;
@property (nonatomic, strong, readwrite) NSString *apiKey;
- (instancetype)initWithConfiguration:(STPPaymentConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
@end
// BongloyAPIClient.m
#import "BongloyAPIClient.h"
static NSString * const APIBaseURL = @"https://api.bongloy.com/v1";
@implementation BongloyAPIClient
- (instancetype)initWithConfiguration:(STPPaymentConfiguration *)configuration {
NSString *publishableKey = [configuration.publishableKey copy];
self = [super initWithConfiguration:configuration];
if (self) {
_apiKey = publishableKey;
_apiURL = [NSURL URLWithString:APIBaseURL];
_urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
}
return self;
}
@end
Create a bridging header for BongloyAPIClient
#import "BongloyAPIClient.h"
let cardParams = STPCardParams()
cardParams.number = "6200000000000005"
cardParams.expMonth = 12
cardParams.expYear = 2020
cardParams.cvc = "123"
BongloyAPIClient.shared().createTokenWithCard(cardParams) { (token: STPToken?, error: Error?) in
guard let token = token, error == nil else {
// Present error to user...
return
}
submitTokenToBackend(token, completion: { (error: Error?) in
if let error = error {
// Present error to user...
}
else {
// Continue with payment...
}
})
}
Once you’ve securely collected and tokenized your customer's credit card you can charge the card immediately or save it for later. Unlike tokenization, which occurs in the browser, charge attempts are made from your server, normally using one of our client libraries. If you haven't already, install the library for your favorite language now.
On your server, grab the Bongloy token in the POST parameters submitted by your form. From there, it’s one simple API call to charge the card:
$ curl https://api.bongloy.com/v1/charges \
-u sk_test_abcde...: \
-d amount=999 \
-d currency=usd \
-d source=token_id \
-d "metadata[order_id]=6735" \
-d "description=Example Charge"
That's it! If the charge creation request succeeds, the card has been successfully charged. If the charge attempt fails, we'll return an error instead.
Note that a token can only be used once, and within a few minutes of creation. To support multiple charges, or future charges save the card token instead of charging it.
You can set the statement descriptor dynamically on every charge request
with the statement_descriptor
argument on the Charge
object:
$ curl https://api.bongloy.com/v1/charges \
-u sk_test_abcde...: \
-d amount=999 \
-d currency=usd \
-d source=token_id \
-d "description=Example Charge" \
-d "statement_descriptor=Custom descriptor"
Statement descriptors are limited to 22 characters,
cannot use the special characters ><'"
and must
not consist solely of numbers.
Bongloy supports adding metadata to the most common requests you make, such as processing charges. Metadata isn't shown to customers or displayed on their statements.
Through metadata, you can associate other information, which is meaningful to you, with Bongloy activity. Any metadata you include is viewable in the Dashboard (e.g., when looking at the page for an individual charge), and is also available in common reports and exports. As an example, your store's order ID can be attached to the charge used to pay for that order. Doing so allows you, your accountant, or your finance team to easily reconcile charges in Bongloy to orders in your system.
$ curl https://api.bongloy.com/v1/charges \
-u sk_test_abcde...: \
-d amount=999 \
-d currency=usd \
-d source=token_id \
-d "description=Example Charge" \
-d "metadata[order_id]=6735"
When you collect a customer's payment information, a Bongloy token is created. This token can only be used once, but that doesn't mean you have to request your customer's card details for every payment.
Bongloy provides a
Customer
object that makes it easy to save you customer's payment information for later use.
You can use Customer
objects for creating subscriptions or future one-off charges.
To make a card available for later charging, create a new Customer
instead of a Charge
by providing their tokenized card information
and optionally an email address.
Be certain to store the customer ID on your side for later use.
You can subsequently charge that customer by passing the customer ID,
instead of a card representation in the charge request.
# Create a customer
$ curl https://api.bongloy.com/v1/customers \
-u sk_test_abcde...: \
-d source=token_id \
-d "email=paying.user@example.com"
# YOUR CODE: Save the customer ID and other info in a database for later.
# Charge the customer instead of the card
$ curl https://api.bongloy.com/v1/charges \
-u sk_test_abcde...: \
-d amount=1000 \
-d currency=usd \
-d customer=customer_id
# When it's time to charge the customer again, use the customer ID.
$ curl https://api.bongloy.com/v1/charges \
-u sk_test_abcde...: \
-d amount=1500 \
-d currency=usd \
-d customer=customer_id
Bongloy supports both static and dynamic QR Code payments. You can download your static QR Code from your account settings page.. In order to integrate dynamic QR Code Payments into your application follow the steps below:
Start by creating a Payment Intent on the server and pass its client secret to the client instead of passing the entire PaymentIntent object. The payment is confirmed on the client, and your server monitors webhooks to detect when the payment completes successfully or fails.
When you create the PaymentIntent, you can specify options like the amount
and currency
. Specify qr_code
as the payment method type:
$ curl https://api.bongloy.com/v1/payment_intents \
-u sk_test_abcde...: \
-d amount=1000 \
-d currency=USD \
-d "payment_method_types[]"=qr_code
The Payment Intent contains a client secret, a key that is unique to the individual Payment Intent.
On the client side of your application, the client secret is used as a parameter when invoking Bongloy.confirmQRCodePayment
from Bongloy.js to display the QR Code.
To use the client secret, you must obtain it from the Payment Intent on your server and pass it to the client side.
Bongloy.confirmQRCodePayment("[client_secret]", function(status, data) {
document.getElementById("qr-code").src = data.qr_code.image_data_url
});
Bongloy can send webhook events to your server to notify you when the status of a Payment Intent changes. This is useful for purposes like determining when to fulfill the goods and services purchased by the customer.
Your integration should not attempt to handle order fulfillment on the client side because it is possible for customers to leave the page after payment is complete but before the fulfillment process initiates.
Instead, we strongly recommend using webhooks to monitor the payment_intent.succeeded
event and handle its completion asynchronously instead of attempting to initiate fulfillment on the client side.
To handle a webhook event, create a route on your server and configure a corresponding webhook endpoint in the Dashboard.
Bongloy sends the payment_intent.succeeded
event when payment is successful
and the payment_intent.payment_failed
event when payment isn’t successful.
The webhook payload includes the Payment Intent object. The following example shows a payment_intent.succeeded
event:
{
"id": "a6b228a6-00da-4591-a4df-dd2d4da4fa57",
"data": {
"object": {
"id": "a1201e32-91d0-4552-84d0-690fb6e6287b",
"amount": 10000,
"object": "payment_intent",
"status": "succeeded",
"charges": {
"url": "/v1/charges?payment_intent=a1201e32-91d0-4552-84d0-690fb6e6287b",
"data": [
{
"id": "efce24eb-a78b-40f6-a4a4-ff68994028cc",
"paid": true,
"amount": 10000,
"object": "charge",
"source": {
"id": "8b4b9683-59b7-46e2-b5b9-dbc5233edcba",
"name": null,
"brand": "UnionPay",
"last4": "2354",
"object": "card",
"country": null,
"created": 1603786481,
"customer": null,
"exp_year": null,
"livemode": false,
"cvc_check": "unchecked",
"exp_month": null,
"address_zip": null,
"fingerprint": "571e945d56f32b5218b1b986c4cc2fdc9bcb9d053145b8a31ed677a7ed6be360",
"address_city": null,
"address_line1": null,
"address_line2": null,
"address_state": null,
"address_country": null,
"address_zip_check": "unchecked",
"address_line1_check": "unchecked"
},
"status": "succeeded",
"created": 1603786485,
"dispute": null,
"outcome": {
"type": "authorized",
"reason": null,
"risk_level": "normal",
"network_status": "approved_by_network"
},
"refunds": {
"url": "/v1/charges?payment_intent=a1201e32-91d0-4552-84d0-690fb6e6287b",
"data": [
],
"object": "list",
"has_more": false
},
"captured": true,
"currency": "USD",
"customer": null,
"livemode": false,
"metadata": {
},
"refunded": false,
"application": null,
"description": null,
"failure_code": null,
"amount_refunded": 0,
"application_fee": null,
"failure_message": null,
"balance_transaction": "b0f2edd5-6847-48d7-9c6d-c0d4db8bc47d",
"statement_descriptor": null,
"application_fee_amount": null
}
],
"object": "list",
"has_more": false
},
"created": 1603786481,
"currency": "USD",
"livemode": false,
"metadata": {
},
"client_secret": "mCHuwj5jSstvuxn1zZN3ZyZr",
"payment_method_types": [
"qr_code"
]
}
},
"type": "payment_intent.succeeded",
"object": "event",
"created": 1603786485,
"livemode": false
}
Marketplaces and platforms use Bongloy Connect to accept money and pay out to third parties. Connect enables you to use the Bongloy API on behalf of connected accounts.
Connect is a flexible combination of features designed to support a wide range of use cases:
A user connects to your platform using the following OAuth connection flow:
client_id
.
When these steps are done, API requests can be made on behalf of the user with their account ID.
To get started with your integration, you need two pieces of information from your platform settings.
client_id
, a unique identifier for your platform, generated by Bongloy
redirect_uri
,
a page on your website to which the user is redirected after connecting their account
(or failing to, should that be the case), set by you
With these two pieces of information in hand,
you're ready to create the OAuth link.
We recommend showing a
Connect button
that sends users to our authorize_url
endpoint.
There are two endpoints, one for the sandbox and one for production:
https://sandbox.bongloy.com/oauth/authorize?client_id=CLIENT_ID&redirect_uri=https%3A%2F%2Fwww.example.com%2Fauth%2Fbongloy%2Fcallback&response_type=code
https://www.bongloy.com/oauth/authorize?client_id=CLIENT_ID&redirect_uri=https%3A%2F%2Fwww.example.com%2Fauth%2Fbongloy%2Fcallback&response_type=code
The Bongloy endpoint should receive at least these three parameters:
response_type
, with a value of code
client_id
redirect_uri
. Note this value should be URL encoded
e.g. https://www.example.com/auth/bongloy/callback
should be encoded as
https%3A%2F%2Fwww.example.com%2Fauth%2Fbongloy%2Fcallback
To prevent CSRF attacks, add the state
parameter,
passing along a unique token as the value.
We'll include the state
you gave us when we redirect the user back to your site.
Here's how the above URL can be presented to your user to begin the connection. This example links to the sandbox endpoint:
After the user clicks the link on your site, they'll be taken to Bongloy's website where they'll be prompted to allow or deny the connection to your platform.
After the user connects their existing or newly created account to your platform,
they are redirected back to your site,
to the URL established as your platform's redirect_uri
.
For successful connections, we'll pass along in the URL:
state
value, if provided
https://www.example.com/auth/bongloy/callback?code=AUTHORIZATION_CODE
If the authorization was denied by the user, they'll still be redirected back to your site, but the URL includes an error instead of the authorization code:
https://www.example.com/auth/bongloy/callback?error=access_denied&error_description=The%20user%20denied%20your%20request
Assuming no error occurred,
the last step is to use the provided code
to make a POST request
to our access_token_url
endpoint to fetch the user's Bongloy credentials.
There are two endpoints, one for the sandbox and one for production:
https://sandbox.bongloy.com/oauth/token
https://www.bongloy.com/oauth/token
Below is an example request to our sandbox endpoint:
$ curl https://sandbox.bongloy.com/oauth/token \
-d "client_id=CLIENT_ID" \
-d "client_secret=CLIENT_SECRET" \
-d "code=AUTHORIZATION_CODE" \
-d "grant_type=authorization_code" \
-d "redirect_uri=https://www.example.com/auth/bongloy/callback"
Bongloy returns a response containing the authentication credentials for the user:
{
"access_token": "ACCESS_TOKEN",
"bongloy_account_id": "ACCOUNT_ID",
"publishable_key": "PUBLISHABLE_KEY",
"token_type": "Bearer"
}
If there was a problem, we instead return an error:
{
"error": "invalid_grant",
"error_description": "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."
}
You’re done! The user is now connected to your platform.
Store the bongloy_account_id
in your database;
this is the Bongloy account ID for the new account.
You'll use this value to authenticate as the connected account by passing it
into requests in the Bongloy-Account
header.
In your application, you might want to consider using a dedicated OAuth client library to simplify these steps. To find an OAuth library for your language or framework, you can refer to the list of client libraries on the OAuth website.
An account.application.deauthorized
event occurs when a user disconnects your platform
from their account.
By watching for this event via
webhooks
you can perform any necessary cleanup on your servers.
In order to authenticate as a user under your platform use the Bongloy-Account
header.
This requires that you store the connected account's ID when connecting the account to your platform.
This curl request performs a refund of a charge on behalf of a connected account:
$ curl https://api.bongloy.com/v1/refunds \
-u sk_test_abcde...: \
-d charge=charge_id \
-H "Bongloy-Account: CONNECTED_BONGLOY_ACCOUNT_ID"
With Bongloy Connect, you can make charges directly on the connected account and take fees in the process.
When creating charges on the connected account, the connected account is responsible for the cost of the Bongloy fees, refunds, and chargebacks.
To create a charge the connected account, perform a standard create charge request using your platform's secret key while authenticated as the connected account:
$ curl https://api.bongloy.com/v1/charges \
-u sk_test_abcde...: \
-d amount=1000 \
-d currency=usd \
-d source=token_id \
-H "Bongloy-Account: CONNECTED_BONGLOY_ACCOUNT_ID"
When creating charges on the connected account,
you must provide a token created under the connected account.
You create a token under the connected account by passing the
Bongloy-Account
header. This is done automatically for you when
using Bongloy.js.
Just pass the the bongloyAccount
option when
setting your publishable key.
Charges created directly on the connected account are only reported on that account; they aren't shown in your platform's Dashboard, exports, or other reporting, although you can always retrieve this information via the API.
With Connect, your platform can take an application fee on charges.
To apply an application fee on a charge, pass an optional
application_fee_amount
value as a positive integer:
$ curl https://api.bongloy.com/v1/charges \
-u sk_test_abcde...: \
-d amount=1000 \
-d currency=usd \
-d source=token_id \
-d application_fee_amount=123 \
-H "Bongloy-Account: CONNECTED_BONGLOY_ACCOUNT_ID"
There are three things to note about application fees:
The resulting charge's
balance transaction
includes a detailed fee breakdown
of both the Bongloy and application fees.
To provide a better reporting experience, an application fee object
is created once the fee is collected.
Use the amount
property on the application fee object for reporting.
You can then access these objects with the
Application Fees
endpoint.
Earned application fees are added to your available account balance on the same schedule as funds from regular Bongloy charges. Application fees are viewable in the Collected Fees section of the Dashboard.
When you specify an application fee on a charge, the fee amount is transferred to your platform's Bongloy account. When processing a charge directly on the connected account, the charge amount, less the Bongloy fees and application fee, is deposited into the connected account. For example, if a charge of $10 with a $1.23 application fee is made (as in the example above), $1.23 is transferred to your platform account, and $8.23 ($10 - $0.54 - $1.23) is netted in the connected account (assuming standard Bongloy fees.
Just as platforms can create charges on connected accounts, they can also create refunds of charges on connected accounts. To refund a charge on a connected account, perform a standard create refund request using your platform's secret key while authenticated as the connected account.
Wherever possible, Bongloy's API is compatible with Stripe's REST API. The examples in the API reference are cURL commands. While cURL is useful for testing, we highly recommend that you make use of Stripe's API libraries when building your application.
The examples in this documentation actually work. You can perform the requests using your test-mode secret API key which is linked to your account. If you login to the Bongloy Sandbox, your API keys will be automatically pre-filled for you.
The Bongloy API uses API keys to authenticate requests. You can view and manage your API keys in the Bongloy Dashboard.
Test mode secret keys have the prefix
sk_test_
and live mode secret keys have the prefix sk_live_
.
Your API keys carry many privileges, so be sure to keep them secure! Do not share your secret API keys in publicly accessible areas such as GitHub, client-side code, and so forth.
Authentication to the API is performed via HTTP Basic Auth Provide your API key as the basic auth username value. You do not need to provide a password.
All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail.
$ curl https://api.bongloy.com/v1/charges \
-u sk_test_abcde...:
# The colon prevents curl from asking for a password.
All top-level API resources have support for bulk fetches via "list" API methods.
For instance, you can
list charges,
list customers,
and list refunds.
These list API methods share a common structure, taking at least these three parameters:
limit
, starting_after
, and ending_before
.
Bongloy utilizes cursor-based pagination via the starting_after
and ending_before
parameters.
Both parameters take an existing object ID value (see below)
and return objects in reverse chronological order.
The ending_before
parameter returns objects listed before the named object.
The starting_after
parameter returns objects listed after the named object.
If both parameters are provided, only ending_before
is used.
limit
optional, default is 10
starting_after
optional
starting_after
is an object ID that defines your place in the list. For instance,
if you make a list request and receive 100 objects, ending with
obj_foo
, your subsequent call can include
starting_after=obj_foo
in order to fetch the next page of the list.
ending_before
optional
ending_before
is an object ID
that defines your place in the list. For instance,
if you make a list request and receive 100 objects, starting with
obj_bar
, your subsequent call can include
ending_before=obj_bar
in order to fetch the
previous page of the list.
object
string, value is "list"
data
array
has_more
boolean
false
, this set comprises the end of the list.
url
string
$ curl https://api.bongloy.com/v1/charges?limit=3 \
-u sk_test_abcde...: \
-G
{
"has_more": true,
"object": "list",
"url": "/v1/charges",
"data": [
{
"id": "c43b2992-6fe0-485c-a11b-848edeb50270",
"object": "charge",
"created": 1562115476,
"livemode": false,
"amount": 10000,
"amount_refunded": 0,
"balance_transaction": null,
"captured": false,
"currency": "USD",
"customer": null,
"description": "Charge for 1 case of Singha at KTV",
"dispute": null,
"failure_code": null,
"failure_message": null,
"application": null,
"paid": true,
"refunded": false,
"refunds": {
"has_more": false,
"object": "list",
"url": "/api/v1/charges",
"data": []
},
"source": {
"id": "f59240fc-3871-4729-a5be-2ed1f61f0b67",
"object": "card",
"created": 1562115452,
"livemode": false,
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": "unchecked",
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "UnionPay",
"country": "KH",
"customer": null,
"cvc_check": "unchecked",
"exp_month": 10,
"exp_year": 2021,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"last4": "0005",
"name": null
},
"statement_descriptor": "Singha",
"status": "succeeded",
"metadata": {
"foo": "bar"
},
"outcome": {
"type": "authorized",
"reason": null,
"risk_level": "normal",
"network_status": "approved_by_network"
},
"application_fee_amount": null,
"application_fee": null
},
{...},
{...}
]
}
Some Bongloy objects including
charges,
customers,
and refunds
have a metadata
parameter.
You can use this parameter to attach key-value data to these Bongloy objects.
Metadata is useful for storing additional, structured information on an object. As an example, you could store your user's full name and corresponding unique identifier from your system on a Bongloy Customer object. Metadata is not used by Bongloy. For example, it's not used to authorize or decline a charge and won't be seen by your users unless you choose to show it to them.
Some of the objects listed above also support a description
parameter.
You can use the description
parameter to annotate a charge with,
for example, a human-readable description like 2 shirts for test@example.com
.
Unlike metadata, description is a single string.
Do not store any sensitive information
(personally identifiable information, card details, etc.)
as metadata or in the description
parameter.
$ curl https://api.bongloy.com/v1/charges \
-u sk_test_abcde...: \
-d amount=10000 \
-d currency=usd \
-d source=token_id \
-d "metadata[order_id]=6735" \
-d "description=Charge for 1 case of Singha at KTV"
{
"id": "f1cb560f-e0ac-454e-9bf1-2917bff4d978",
"metadata": {
"order_id": "6735"
},
"description": "Charge for 1 case of Singha at KTV",
...
}
When you collect a transaction fee on top of a charge made for your user (using Connect),
an Application Fee
object is created in your account.
You can list and retrieve application fees.
For details, see Collecting application fees.
Retrieves the details of an application fee that your account has collected.
id
required
Returns the ApplicationFee
object.
curl https://api.bongloy.com/v1/application_fees/8bb212e9-6b57-4df1-8dff-7168f898849d \
-u sk_test_abcde...:
{
"id": "8bb212e9-6b57-4df1-8dff-7168f898849d",
"object": "application_fee",
"account": "91f6012e-79ed-49a6-8d70-4f01a85cb25d",
"amount": 50,
"application": "472d7ef6-8c0a-4aab-a497-921ca258911f",
"balance_transaction": "398ebfe9-2d8a-4296-85eb-8869ccc9e564",
"charge": "ffee13a9-42b9-4682-96eb-43265521ff23",
"currency": "USD",
"created": 1562533549
}
Returns a list of application fees you've previously collected. The application fees are returned in sorted order, with the most recent fees appearing first.
ending_before
optional
ending_before
is an object ID that defines your place in the list.
For instance, if you make a list request and receive 100 objects,
starting with obj_bar
, your subsequent call can
include ending_before=obj_bar
in order to fetch the previous page
of the list.
limit
optional
starting_after
optional
starting_after
is an object ID that defines your place in the list.
For instance, if you make a list request and receive 100 objects,
ending with obj_foo
, your subsequent call can include
starting_after=obj_foo
in order to fetch the next page of the list.
A dictionary with a data
property that contains
an array of up to limit
application fees, starting after
application fee starting_after
. Each entry in the array is a
separate application fee object. If no more application fees are available,
the resulting array will be empty.
curl https://api.bongloy.com/v1/application_fees?limit=3 \
-u sk_test_abcde...:
{
"has_more": false,
"object": "list",
"url": "/v1/application_fees",
"data": [
{
"id": "38c76d87-bab1-4ff7-a8ec-1ae06af89c86",
"object": "application_fee",
"account": "5a21e708-5cd0-4d46-8e78-18bd21be0804",
"amount": 50,
"application": "a6a04f4a-47cf-48b4-980b-e6900d925010",
"balance_transaction": "00627b3b-d236-4b6d-8d30-54326cb9ef51",
"charge": "caa818f1-3d77-4b7b-85b8-21097e83a56a",
"currency": "USD",
"created": 1562533837
}
]
}
This is an object representing your Bongloy balance. You can retrieve it to see the balance currently on your Bongloy account.
You can also retrieve the balance history, which contains a list of transactions that contributed to the balance (charges, payouts, and so forth).
Retrieves the current account balance.
No arguments
Returns a Balance
object for the account that was authenticated in the request.
curl https://api.bongloy.com/v1/balance \
-u sk_test_abcde...:
{
"object": "balance",
"livemode": false,
"available": [
{
"amount": 10000,
"currency": "USD",
"source_types": {
"card": 10000
}
}
],
"pending": [
{
"amount": 5000,
"currency": "USD",
"source_types": {
"card": 5000
}
}
]
}
Retrieves the balance transaction with the given ID.
id
required
Returns the BalanceTransaction
object.
curl https://api.bongloy.com/v1/balance/history/f488a05a-4359-409b-9472-f3b07b1d8e12 \
-u sk_test_abcde...:
{
"id": "f488a05a-4359-409b-9472-f3b07b1d8e12",
"object": "balance_transaction",
"amount": 10000,
"available_on": 1558915200,
"created": 1558343366,
"currency": "USD",
"fee": 1200,
"fee_details": [
{
"amount": 200,
"currency": "USD",
"type": "tax"
},
{
"amount": 1000,
"currency": "USD",
"type": "bongloy_fee"
}
],
"net": 8800,
"status": "available",
"source": "dd08b150-ac0f-477a-ae56-14695079edc7",
"type": "charge"
}
Returns a list of transactions that have contributed to the Bongloy account balance (e.g., charges, payouts, and so forth). The transactions are returned in sorted order, with the most recent transactions appearing first.
ending_before
optional
ending_before
is an object ID that defines your place in the list.
For instance, if you make a list request and receive 100 objects,
starting with obj_bar
, your subsequent call can
include ending_before=obj_bar
in order to fetch the previous page
of the list.
limit
optional
starting_after
optional
starting_after
is an object ID that defines your place in the list.
For instance, if you make a list request and receive 100 objects,
ending with obj_foo
, your subsequent call can include
starting_after=obj_foo
in order to fetch the next page of the list.
A dictionary with a data
property that contains
an array of up to limit
transactions, starting after
transaction starting_after
. Each entry in the array is a
separate transaction object. If no more transactions are available,
the resulting array will be empty.
curl https://api.bongloy.com/v1/balance/history?limit=3 \
-u sk_test_abcde...:
{
"has_more": true,
"object": "list",
"url": "/v1/balance/history",
"data": [
{
"id": "f488a05a-4359-409b-9472-f3b07b1d8e12",
"object": "balance_transaction",
"amount": 10000,
"available_on": 1558915200,
"created": 1558343366,
"currency": "USD",
"fee": 2000,
"fee_details": [
{
"amount": 800,
"currency": "USD",
"type": "tax"
},
{
"amount": 1200,
"currency": "USD",
"type": "bongloy_fee"
}
],
"net": 8000,
"status": "available",
"source": "dd08b150-ac0f-477a-ae56-14695079edc7",
"type": "charge"
},
{...},
{...}
]
}
To charge a credit card, you create a new Charge
object.
You can retrieve and refund individual charges as well as list all charges.
Charges are identified by a unique, random ID.
To charge a credit card,
you create a new Charge
object.
If your API key is in test mode,
the supplied card won't actually be charged,
though everything else will occur as if in live mode.
(Bongloy assumes that the charge would have completed successfully).
amount
required
100
cents to charge $1.00).
The minimum amount is $1.00 USD.
currency
required
application_fee_amount
optional
Bongloy-Account
header in order to take an application fee.
For more information,
see the application fees
documentation.
capture
optional
true
.
When false
, the charge issues a pre-authorization,
and will need to be
captured
later.
Uncaptured charges expire in seven days.
For more information,
see the
authorizing charges and settling later
documentation.
customer
optional
description
optional
Charge>
object.
It is displayed when in the web interface alongside the charge.
This will be unset if you POST an empty value.
metadata
optional
source
optional
statement_descriptor
optional
RunClub
and the item you're charging for is a race ticket,
you might want to specify a statement_descriptor of
RunClub 5K race ticket
.
The statement descriptor must contain at least one letter,
must not contain ><'"
characters,
and will appear on your customer’s statement in capital letters.
Non-ASCII characters are automatically stripped.
While most banks and card issuers display this information consistently,
some might display it incorrectly or not at all.
Returns a Charge
object if the charge succeeded.
Returns an error if something goes wrong.
A common source of error is an invalid or expired card,
or a valid card with insufficient available balance.
To charge a card you first need to create a token that represents the card. You can create a token using Bongloy.js
$ curl https://api.bongloy.com/v1/charges \
-u sk_test_abcde...: \
-d amount=10000 \
-d currency=usd \
-d source=token_id \
-d "description=Charge for 1 case of Singha at KTV" \
-d "statement_descriptor=Singha" \
-d "metadata[foo]=bar"
{
"id": "68868dd7-5b75-4f19-b11a-c74900a73980",
"object": "charge",
"created": 1562114274,
"livemode": false,
"amount": 10000,
"amount_refunded": 0,
"balance_transaction": "ceb8731b-6986-4cdd-a8e7-49b55e9f125c",
"captured": true,
"currency": "USD",
"customer": null,
"description": "Charge for 1 case of Singha at KTV",
"dispute": null,
"failure_code": null,
"failure_message": null,
"application": null,
"paid": true,
"refunded": false,
"refunds": {
"has_more": false,
"object": "list",
"url": "/v1/charges/68868dd7-5b75-4f19-b11a-c74900a73980/refunds",
"data": []
},
"source": {
"id": "cb0a65ff-9a03-4750-9c83-3ca112876875",
"object": "card",
"created": 1562114231,
"livemode": false,
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": "unchecked",
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "UnionPay",
"country": "KH",
"customer": null,
"cvc_check": "unchecked",
"exp_month": 10,
"exp_year": 2021,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"last4": "0005",
"name": null
},
"statement_descriptor": "Singha",
"status": "succeeded",
"metadata": {
"foo": "bar"
},
"outcome": {
"network_status": "approved_by_network",
"risk_level": "normal",
"type": "authorized",
"reason": null
},
"application_fee_amount": null,
"application_fee": null
}
Retrieves the details of a charge that has previously been created. Supply the unique charge ID that was returned from your previous request, and Bongloy will return the corresponding charge information. The same information is returned when creating the charge.
charge
required
Returns the Charge
object.
$ curl https://api.bongloy.com/v1/charges/f1cb560f-e0ac-454e-9bf1-2917bff4d978 \
-u sk_test_abcde...:
{
"id": "68868dd7-5b75-4f19-b11a-c74900a73980",
"object": "charge",
"created": 1562114274,
"livemode": false,
"amount": 10000,
"amount_refunded": 0,
"balance_transaction": "ceb8731b-6986-4cdd-a8e7-49b55e9f125c",
"captured": true,
"currency": "USD",
"customer": null,
"description": "Charge for 1 case of Singha at KTV",
"dispute": null,
"failure_code": null,
"failure_message": null,
"application": null,
"paid": true,
"refunded": false,
"refunds": {
"has_more": false,
"object": "list",
"url": "/v1/charges/68868dd7-5b75-4f19-b11a-c74900a73980/refunds",
"data": []
},
"source": {
"id": "cb0a65ff-9a03-4750-9c83-3ca112876875",
"object": "card",
"created": 1562114231,
"livemode": false,
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": "unchecked",
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "UnionPay",
"country": "KH",
"customer": null,
"cvc_check": "unchecked",
"exp_month": 10,
"exp_year": 2021,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"last4": "0005",
"name": null
},
"statement_descriptor": "Singha",
"status": "succeeded",
"metadata": {
"foo": "bar"
},
"outcome": {
"type": "authorized",
"reason": null,
"risk_level": "normal",
"network_status": "approved_by_network"
},
"application_fee_amount": null,
"application_fee": null
}
Capture the payment of an existing, uncaptured, charge. This is the second half of the two-step payment flow, where first you created a charge with the capture option set to false.
Uncaptured payments expire exactly seven days after they are created. If they are not captured by that point in time, they will be marked as refunded and will no longer be capturable.
charge
required
amount
optional
application_fee_amount
optional
Returns the charge object, with an updated captured property (set to true). Capturing a charge will always succeed, unless the charge is already refunded, expired, captured, or an invalid capture amount is specified, in which case this method will return an error.
$ curl -X POST https://api.bongloy.com/v1/charges/f1cb560f-e0ac-454e-9bf1-2917bff4d978/capture \
-u sk_test_abcde...:
{
"id": "56171c87-9d66-4e8e-b83c-b622a3b22e4f",
"object": "charge",
"created": 1562115953,
"livemode": false,
"amount": 10000,
"amount_refunded": 0,
"balance_transaction": "d4a645f0-4024-4611-bcc9-4696a81c78a1",
"captured": true,
"currency": "USD",
"customer": null,
"description": "Charge for 1 case of Singha at KTV",
"dispute": null,
"failure_code": null,
"failure_message": null,
"application": null,
"paid": true,
"refunded": false,
"refunds": {
"has_more": false,
"object": "list",
"url": "/v1/charges/56171c87-9d66-4e8e-b83c-b622a3b22e4f/refunds",
"data": []
},
"source": {
"id": "117e7e4e-a89e-400b-9fff-8105efc73ac2",
"object": "card",
"created": 1562115764,
"livemode": false,
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": "unchecked",
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "UnionPay",
"country": "KH",
"customer": null,
"cvc_check": "unchecked",
"exp_month": 10,
"exp_year": 2021,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"last4": "0005",
"name": null
},
"statement_descriptor": "Singha",
"status": "succeeded",
"metadata": {
"foo": "bar"
},
"outcome": {
"type": "authorized",
"reason": null,
"risk_level": "normal",
"network_status": "approved_by_network"
},
"application_fee_amount": null,
"application_fee": null
}
Returns a list of charges you’ve previously created. The charges are returned in sorted order, with the most recent charges appearing first.
ending_before
optional
ending_before
is an object ID that defines your place in the list.
For instance, if you make a list request and receive 100 objects,
starting with obj_bar
, your subsequent call can
include ending_before=obj_bar
in order to fetch
the previous page of the list.
limit
optional
starting_after
optional
starting_after
is an object ID that defines your
place in the list. For instance, if you make a list request and
receive 100 objects, ending with obj_foo
,
your subsequent call can include starting_after=obj_foo
in order to fetch the next page of the list.
A dictionary with a data
property that contains
an array of up to limit
charges, starting after
charge starting_after
. Each entry in the array is a
separate charge object. If no more charges are available,
the resulting array will be empty.
$ curl https://api.bongloy.com/v1/charges?limit=3 \
-u sk_test_abcde...: \
-G
{
"has_more": true,
"object": "list",
"url": "/v1/charges",
"data": [
{
"id": "c43b2992-6fe0-485c-a11b-848edeb50270",
"object": "charge",
"created": 1562115476,
"livemode": false,
"amount": 10000,
"amount_refunded": 0,
"balance_transaction": null,
"captured": false,
"currency": "USD",
"customer": null,
"description": "Charge for 1 case of Singha at KTV",
"dispute": null,
"failure_code": null,
"failure_message": null,
"application": null,
"paid": true,
"refunded": false,
"refunds": {
"has_more": false,
"object": "list",
"url": "/api/v1/charges",
"data": []
},
"source": {
"id": "f59240fc-3871-4729-a5be-2ed1f61f0b67",
"object": "card",
"created": 1562115452,
"livemode": false,
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": "unchecked",
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "UnionPay",
"country": "KH",
"customer": null,
"cvc_check": "unchecked",
"exp_month": 10,
"exp_year": 2021,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"last4": "0005",
"name": null
},
"statement_descriptor": "Singha",
"status": "succeeded",
"metadata": {
"foo": "bar"
},
"outcome": {
"type": "authorized",
"reason": null,
"risk_level": "normal",
"network_status": "approved_by_network"
},
"application_fee_amount": null,
"application_fee": null
},
{...},
{...}
]
}
Customer objects allow you to perform recurring charges and track multiple charges that are associated with the same customer. The API allows you to create, delete, and update your customers. You can retrieve individual customers as well as a list of all your customers.
Creates a customer object
description
optional
email
optional
metadata
optional
source
optional
source
will create a new card object and make it the
customer default source.
If you want to add an additional source to an existing customer instead,
use the card creation API.
Returns a Customer
object if the call succeeded. If a source has been attached to the customer, the returned customer object will have a default_source
attribute, which is an ID that can be expanded into the full source details when retrieving the customer.
$ curl https://api.bongloy.com/v1/customers \
-u sk_test_abcde...: \
-d source=token_id \
-d "description=Customer for jenny.rosen@example.com" \
-d "metadata[foo]=bar"
{
"id": "826aacc5-a4c2-4b7a-807a-50c09ed64a41",
"object": "customer",
"created": 1553324006,
"livemode": false,
"default_source": "b817ff09-bd58-4dca-8349-fed5e1d59a67",
"description": "Customer for jenny.rosen@example.com",
"email": null,
"sources": {
"has_more": false,
"object": "list",
"url": "/v1/customers/826aacc5-a4c2-4b7a-807a-50c09ed64a41/sources",
"data": [
{
"id": "b817ff09-bd58-4dca-8349-fed5e1d59a67",
"object": "card",
"created": 1553323914,
"livemode": false,
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": "unchecked",
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "UnionPay",
"country": "KH",
"customer": "826aacc5-a4c2-4b7a-807a-50c09ed64a41",
"cvc_check": "unchecked",
"exp_month": 12,
"exp_year": 2019,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"last4": "0005",
"name": null
}
]
},
"metadata": {
"foo": "bar"
}
}
Retrieves the details of an existing customer. You need only supply the unique customer identifier that was returned upon customer creation.
id
required
Returns the Customer
object.
$ curl https://api.bongloy.com/v1/customers/826aacc5-a4c2-4b7a-807a-50c09ed64a41 \
-u sk_test_abcde...:
{
"id": "826aacc5-a4c2-4b7a-807a-50c09ed64a41",
"object": "customer",
"created": 1553324006,
"livemode": false,
"default_source": "b817ff09-bd58-4dca-8349-fed5e1d59a67",
"description": "Customer for jenny.rosen@example.com",
"email": null,
"sources": {
"has_more": false,
"object": "list",
"url": "/v1/customers/826aacc5-a4c2-4b7a-807a-50c09ed64a41/sources",
"data": [
{
"id": "b817ff09-bd58-4dca-8349-fed5e1d59a67",
"object": "card",
"created": 1553323914,
"livemode": false,
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": "unchecked",
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "UnionPay",
"country": "KH",
"customer": "826aacc5-a4c2-4b7a-807a-50c09ed64a41",
"cvc_check": "unchecked",
"exp_month": 12,
"exp_year": 2019,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"last4": "0005",
"name": null
}
]
},
"metadata": {
"foo": "bar"
}
}
Returns a list of your customers. The customers are returned sorted by creation date, with the most recent customers appearing first.
ending_before
optional
ending_before
is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, starting with obj_bar
, your subsequent call can include ending_before=obj_bar
in order to fetch the previous page of the list.
limit
optional
starting_after
optional
starting_after
is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, ending with obj_foo
, your subsequent call can include starting_after=obj_foo
in order to fetch the next page of the list.
A dictionary with a data
property that contains an array of up to limit
customers, starting after customer starting_after
. Each entry in the array is a separate customer object. If no more customers are available, the resulting array will be empty.
$ curl https://api.bongloy.com/v1/customers?limit=3 \
-u sk_test_abcde...: \
-G
{
"has_more": false,
"object": "list",
"url": "/v1/customers",
"data": [
{
"id": "826aacc5-a4c2-4b7a-807a-50c09ed64a41",
"object": "customer",
"created": 1553324006,
"livemode": false,
"default_source": "b817ff09-bd58-4dca-8349-fed5e1d59a67",
"description": "Customer for jenny.rosen@example.com",
"email": null,
"sources": {
"has_more": false,
"object": "list",
"url": "/v1/customers/826aacc5-a4c2-4b7a-807a-50c09ed64a41/sources",
"data": [
{
"id": "b817ff09-bd58-4dca-8349-fed5e1d59a67",
"object": "card",
"created": 1553323914,
"livemode": false,
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": "unchecked",
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "UnionPay",
"country": "KH",
"customer": "826aacc5-a4c2-4b7a-807a-50c09ed64a41",
"cvc_check": "unchecked",
"exp_month": 12,
"exp_year": 2019,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"last4": "0005",
"name": null
}
]
},
"metadata": {
"foo": "bar"
}
},
{...},
{...}
]
}
You can store multiple cards on a customer in order to charge the customer later.
When you create a new card, you must specify a customer to create it on. If the card's owner has no default card, then the new card will become the default. However, if the owner already has a default then it will not change.
source
required
Returns a Card
object.
To create a card you first need to create a customer and a token that represents the customer's card. You can create a customer by using the Customers API. For the token, you can create one using Bongloy.js
$ curl https://api.bongloy.com/v1/customers/826aacc5-a4c2-4b7a-807a-50c09ed64a41/sources \
-u sk_test_abcde...: \
-d source=token_id
{
"id": "b783dfe1-5b76-4005-8adf-a53dd5faa9da",
"object": "card",
"created": 1553324655,
"livemode": false,
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": "unchecked",
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "UnionPay",
"country": "KH",
"customer": "826aacc5-a4c2-4b7a-807a-50c09ed64a41",
"cvc_check": "unchecked",
"exp_month": 12,
"exp_year": 2019,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"last4": "0007",
"name": null
}
You can always see the 10 most recent cards directly on a customer; this method lets you retrieve details about a specific card stored on the customer.
id
required
Returns the Card
object.
$ curl https://api.bongloy.com/v1/customers/826aacc5-a4c2-4b7a-807a-50c09ed64a41/sources/b783dfe1-5b76-4005-8adf-a53dd5faa9da \
-u sk_test_abcde...:
{
"id": "b783dfe1-5b76-4005-8adf-a53dd5faa9da",
"object": "card",
"created": 1553324655,
"livemode": false,
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": "unchecked",
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "UnionPay",
"country": "KH",
"customer": "826aacc5-a4c2-4b7a-807a-50c09ed64a41",
"cvc_check": "unchecked",
"exp_month": 12,
"exp_year": 2019,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"last4": "0007",
"name": null
}
You can delete cards from a customer.
If you delete a card that is currently the default source, then the most recently added source will become the new default. If you delete a card that is the last remaining source on the customer, then the default_source
attribute will become null.
id
required
204
No Content
$ curl https://api.bongloy.com/v1/customers/826aacc5-a4c2-4b7a-807a-50c09ed64a41/sources/b783dfe1-5b76-4005-8adf-a53dd5faa9da \
-u sk_test_abcde...: \
-X DELETE
204
No Content
You can see a list of the cards belonging to a customer. Note that the 10 most recent sources are always available on the Customer object. If you need more than those 10, you can use this API method and the limit and starting_after parameters to page through additional cards.
customer
required
ending_before
optional
ending_before
is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, starting with obj_bar
, your subsequent call can include ending_before=obj_bar
in order to fetch the previous page of the list.
limit
optional
starting_after
optional
starting_after
is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, ending with obj_foo
, your subsequent call can include starting_after=obj_foo
in order to fetch the next page of the list.
Returns a list of the cards stored on the customer.
$ curl https://api.bongloy.com/v1/customers/826aacc5-a4c2-4b7a-807a-50c09ed64a41/sources?limit=3 \
-u sk_test_abcde...: \
-G
{
"has_more": false,
"object": "list",
"url": "/v1/customers/826aacc5-a4c2-4b7a-807a-50c09ed64a41/sources",
"data": [
{
"id": "b783dfe1-5b76-4005-8adf-a53dd5faa9da",
"object": "card",
"created": 1553324655,
"livemode": false,
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": "unchecked",
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "UnionPay",
"country": "KH",
"customer": "826aacc5-a4c2-4b7a-807a-50c09ed64a41",
"cvc_check": "unchecked",
"exp_month": 12,
"exp_year": 2019,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"last4": "0007",
"name": null
},
{...},
{...}
]
}
Events are our way of letting you know when something interesting happens in your account. When an interesting event occurs, we create a new Event
object.
Retrieves the details of an event. Supply the unique identifier of the event, which you might have received in a webhook.
id
required
Returns an Event
object if a valid identifier was provided. All events share a common structure, detailed to the right. The only property that will differ is the data property.
$ curl https://api.bongloy.com/v1/events/dd37b8f1-cb74-4631-8352-e7eea3513483 \
-u sk_test_abcde...:
{
"id": "dd37b8f1-cb74-4631-8352-e7eea3513483",
"object": "event",
"created": 1561002988,
"livemode": false,
"data": {
"object": {
"id": "b032a116-f561-44e9-98a1-73cfb5e1f5cb",
"paid": true,
"amount": 2000,
"object": "charge",
"source": {
"id": "c91a9c0e-fc66-4260-b2ee-cebb477425ae",
"name": null,
"brand": "UnionPay",
"last4": "0005",
"object": "card",
"country": "KH",
"created": 1561002963,
"customer": null,
"exp_year": 2021,
"livemode": false,
"cvc_check": "unchecked",
"exp_month": 1,
"address_zip": null,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"address_city": null,
"address_line1": null,
"address_line2": null,
"address_state": null,
"address_country": null,
"address_zip_check": "unchecked",
"address_line1_check": "unchecked"
},
"status": "succeeded",
"created": 1561002988,
"dispute": null,
"outcome": {
"type": "authorized",
"reason": null,
"risk_level": "normal",
"network_status": "approved_by_network"
},
"refunds": {
"url": "/v1/charges/b032a116-f561-44e9-98a1-73cfb5e1f5cb/refunds",
"data": [],
"object": "list",
"has_more": false
},
"captured": true,
"currency": "USD",
"customer": null,
"livemode": false,
"metadata": {},
"refunded": false,
"application": null,
"description": "\"Charge for jenny.rosen@example.com\"",
"failure_code": null,
"amount_refunded": 0,
"application_fee": null,
"failure_message": null,
"balance_transaction": "1e2b130e-03a5-4635-ba34-fa4fe2f6008b",
"statement_descriptor": null,
"application_fee_amount": null
}
},
"type": "charge.succeeded"
}
Returns a list of events
ending_before
optional
ending_before
is an object ID
that defines your place in the list.
For instance, if you make a list request and receive 100 objects,
starting with obj_bar
, your subsequent call
can include ending_before=obj_bar
in order to fetch
the previous page of the list.
limit
optional
starting_after
optional
starting_after
is an object ID
that defines your place in the list.
For instance, if you make a list request and receive 100 objects,
ending with obj_foo
, your subsequent call can
include starting_after=obj_foo
in order to fetch
the next page of the list.
A dictionary with a data
property that contains an array of up
to limit
refunds, starting after refund starting_after
.
Each entry in the array is a separate refund object.
If no more refunds are available, the resulting array will be empty.
$ curl https://api.bongloy.com/v1/events?limit=3 \
-u sk_test_abcde...: \
-G
{
"has_more": true,
"object": "list",
"url": "/v1/events",
"data": [
{
"id": "dd37b8f1-cb74-4631-8352-e7eea3513483",
"object": "event",
"created": 1561002988,
"livemode": false,
"data": {
"object": {
"id": "b032a116-f561-44e9-98a1-73cfb5e1f5cb",
"paid": true,
"amount": 2000,
"object": "charge",
"source": {
"id": "c91a9c0e-fc66-4260-b2ee-cebb477425ae",
"name": null,
"brand": "UnionPay",
"last4": "0005",
"object": "card",
"country": "KH",
"created": 1561002963,
"customer": null,
"exp_year": 2021,
"livemode": false,
"cvc_check": "unchecked",
"exp_month": 1,
"address_zip": null,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"address_city": null,
"address_line1": null,
"address_line2": null,
"address_state": null,
"address_country": null,
"address_zip_check": "unchecked",
"address_line1_check": "unchecked"
},
"status": "succeeded",
"created": 1561002988,
"dispute": null,
"outcome": {
"type": "authorized",
"reason": null,
"risk_level": "normal",
"network_status": "approved_by_network"
},
"refunds": {
"url": "/v1/charges/b032a116-f561-44e9-98a1-73cfb5e1f5cb/refunds",
"data": [],
"object": "list",
"has_more": false
},
"captured": true,
"currency": "USD",
"customer": null,
"livemode": false,
"metadata": {},
"refunded": false,
"application": null,
"description": "\"Charge for jenny.rosen@example.com\"",
"failure_code": null,
"amount_refunded": 0,
"application_fee": null,
"failure_message": null,
"balance_transaction": "1e2b130e-03a5-4635-ba34-fa4fe2f6008b",
"statement_descriptor": null,
"application_fee_amount": null
}
},
"type": "charge.succeeded"
},
{...},
{...}
]
}
This is a list of all the types of events we currently send We may add more at any time, so in developing and maintaining your code, you should not assume that only these types exist.
You'll notice that these events follow a pattern: resource.event
.
Our goal is to design a consistent system that makes things easier to anticipate
and code against.
account.application.authorized
describes an application
account.application.deauthorized
describes an application
account.updated
describes an account
charge.captured
describes a charge
charge.expired
describes a charge
charge.failed
describes a charge
charge.refund.updated
describes a refund
charge.refunded
describes a charge
charge.succeeded
describes a charge
payment_intent.payment_failed
describes a payment_intent
payment_intent.succeeded
describes a payment_intent
A Payment Intent guides you through the process of collecting a payment from your customer. We recommend that you create exactly one Payment Intent for each order or customer session in your system. You can reference the Payment Intent later to see the history of payment attempts for a particular session.
A Payment Intent transitions through multiple statuses throughout its lifetime as it interfaces with Bongloy.js to perform authentication flows and ultimately creates at most one successful charge.
amount
required
100
cents to charge $1.00).
The minimum amount is $1.00 USD.
currency
required
payment_method_types
required
qr_code
.
metadata
optional
curl https://api.bongloy.com/v1/payment_intents \
-u sk_test_abcde...: \
-d amount=1000 \
-d currency=USD \
-d "payment_method_types[]"=qr_code
{
"id": "bc2c4857-dcd7-456e-87ac-a43e7c129070",
"object": "payment_intent",
"created": 1603788889,
"livemode": false,
"payment_method_types": [
"qr_code"
],
"client_secret": "SJFjwcUEfFj5srtsuNa4DP53",
"amount": 1000,
"currency": "USD",
"status": "requires_payment_method",
"metadata": {},
"charges": {
"has_more": false,
"object": "list",
"url": "/v1/charges?payment_intent=bc2c4857-dcd7-456e-87ac-a43e7c129070",
"data": []
}
}
Retrieves the details of an existing payment intent.
payment_intent_id
required
Returns the Payment Intent
object.
$ curl https://api.bongloy.com/v1/payment_intents/bc2c4857-dcd7-456e-87ac-a43e7c129070 \
-u sk_test_abcde...:
{
"id": "bc2c4857-dcd7-456e-87ac-a43e7c129070",
"object": "payment_intent",
"created": 1603788889,
"livemode": false,
"payment_method_types": [
"qr_code"
],
"client_secret": "SJFjwcUEfFj5srtsuNa4DP53",
"amount": 1000,
"currency": "USD",
"status": "requires_payment_method",
"metadata": {},
"charges": {
"has_more": false,
"object": "list",
"url": "/v1/charges?payment_intent=bc2c4857-dcd7-456e-87ac-a43e7c129070",
"data": []
}
}
amount
optional
100
cents to charge $1.00).
The minimum amount is $1.00 USD.
currency
optional
metadata
optional
curl -XPATCH https://api.bongloy.com/v1/payment_intents/bc2c4857-dcd7-456e-87ac-a43e7c129070 \
-u sk_test_abcde...: \
-d amount=2000 \
-d currency=USD
{
"id": "bc2c4857-dcd7-456e-87ac-a43e7c129070",
"object": "payment_intent",
"created": 1603788889,
"livemode": false,
"payment_method_types": [
"qr_code"
],
"client_secret": "SJFjwcUEfFj5srtsuNa4DP53",
"amount": 2000,
"currency": "USD",
"status": "requires_payment_method",
"metadata": {},
"charges": {
"has_more": false,
"object": "list",
"url": "/v1/charges?payment_intent=bc2c4857-dcd7-456e-87ac-a43e7c129070",
"data": []
}
}
Returns a list of all payment intetns you've previously created. The payment intents are returned in sorted order, with the most recent payment intents appearing first.
ending_before
optional
ending_before
is an object ID
that defines your place in the list.
For instance, if you make a list request and receive 100 objects,
starting with obj_bar
,
your subsequent call can include ending_before=obj_bar
in order to fetch the previous page of the list.
limit
optional
starting_after
optional
starting_after
is an object ID that defines your place in the list.
For instance, if you make a list request and receive 100 objects,
ending with obj_foo
, your subsequent call can
include starting_after=obj_foo
in order to fetch
the next page of the list.
A dictionary with a data
property that contains an array
of up to limit
refunds, starting after refund starting_after
.
Each entry in the array is a separate refund object.
If no more refunds are available, the resulting array will be empty.
$ curl https://api.bongloy.com/v1/payment_intents?limit=3 \
-u sk_test_abcde...: \
-G
{
"has_more": true,
"object": "list",
"url": "/v1/payment_intents",
"data": [
{
"id": "bc2c4857-dcd7-456e-87ac-a43e7c129070",
"object": "payment_intent",
"created": 1603788889,
"livemode": false,
"payment_method_types": [
"qr_code"
],
"client_secret": "SJFjwcUEfFj5srtsuNa4DP53",
"amount": 1000,
"currency": "USD",
"status": "requires_payment_method",
"metadata": {},
"charges": {
"has_more": false,
"object": "list",
"url": "/v1/payment_intents",
"data": []
}
},
{...},
{...}
]
}
Refund
objects allow you to refund a charge that has previously
been created but not yet refunded. Funds will be refunded to the credit or debit card
that was originally charged.
When you create a new refund, you must specify a charge to create it on.
Creating a new refund will refund a charge that has previously been created but not yet refunded. Funds will be refunded to the credit or debit card that was originally charged. The fees you were originally charged are also refunded.
You can optionally refund only part of a charge. You can do so as many times as you wish until the entire charge has been refunded.
Once entirely refunded, a charge can't be refunded again. This method will return an error when called on an already-refunded charge, or when trying to refund more money than is left on a charge.
charge
required
amount
optional
metadata
optional
Returns a Refund
object if the refund succeeded.
Returns an error if the charge has already been refunded or an invalid charge
identifier was provided.
To create a refund you first need to create a charge You can create a charge by using the Charges API.
curl -X POST https://api.bongloy.com/v1/refunds \
-u sk_test_abcde...: \
-d "charge=<charge_id>"
{
"id": "3ab28291-139e-4635-a65d-01d4f422436b",
"object": "refund",
"created": 1553326197,
"amount": 1000,
"balance_transaction": "6ce5cdad-fb62-4a96-a82f-2c814663afc8",
"charge": "33be96dd-ce44-49b3-91b7-b21f9fcb33c2",
"currency": "USD",
"metadata": {},
"status": "succeeded",
"failure_balance_transaction": null
}
Retrieves the details of an existing refund.
refund_id
required
Returns the Refund
object.
$ curl https://api.bongloy.com/v1/refunds/3ab28291-139e-4635-a65d-01d4f422436b \
-u sk_test_abcde...:
{
"id": "3ab28291-139e-4635-a65d-01d4f422436b",
"object": "refund",
"created": 1553326197,
"amount": 1000,
"balance_transaction": "6ce5cdad-fb62-4a96-a82f-2c814663afc8",
"charge": "33be96dd-ce44-49b3-91b7-b21f9fcb33c2",
"currency": "USD",
"metadata": {},
"status": "succeeded",
"failure_balance_transaction": null
}
Returns a list of all refunds you've previously created. The refunds are returned in sorted order, with the most recent refunds appearing first. For convenience, the 10 most recent refunds are always available by default on the charge object.
ending_before
optional
ending_before
is an object ID
that defines your place in the list.
For instance, if you make a list request and receive 100 objects,
starting with obj_bar
,
your subsequent call can include ending_before=obj_bar
in order to fetch the previous page of the list.
limit
optional
starting_after
optional
starting_after
is an object ID that defines your place in the list.
For instance, if you make a list request and receive 100 objects,
ending with obj_foo
, your subsequent call can
include starting_after=obj_foo
in order to fetch
the next page of the list.
A dictionary with a data
property that contains an array
of up to limit
refunds, starting after refund starting_after
.
Each entry in the array is a separate refund object.
If no more refunds are available, the resulting array will be empty.
$ curl https://api.bongloy.com/v1/refunds?limit=3 \
-u sk_test_abcde...: \
-G
{
"has_more": true,
"object": "list",
"url": "/v1/refunds",
"data": [
{
"id": "3ab28291-139e-4635-a65d-01d4f422436b",
"object": "refund",
"created": 1553326197,
"amount": 1000,
"balance_transaction": "6ce5cdad-fb62-4a96-a82f-2c814663afc8",
"charge": "33be96dd-ce44-49b3-91b7-b21f9fcb33c2",
"currency": "USD",
"metadata": {},
"status": "succeeded",
"failure_balance_transaction": null
},
{...},
{...}
]
}
Token
objects allow you to create charges on a connected account using
shared customers.
This endpoint is only applicable for
Bongloy Connect.
Creates a single-use token that represents a credit card's details. You can use this token to create a charge on a connected account.
customer
required
Returns a Token
object if successful.
$ curl https://api.bongloy.com/v1/tokens \
-u sk_test_abcde...: \
-d customer=customer_id
{
"id": "3a3f1e44-2cab-40d5-b3f3-fc052d63f03f",
"object": "token",
"created": 1562808012,
"livemode": false,
"card": {
"id": "00e5bf0d-f874-49e1-b91b-cf4bded64611",
"object": "card",
"created": 1562808012,
"livemode": false,
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": "unchecked",
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": "unchecked",
"brand": "UnionPay",
"country": "KH",
"customer": null,
"cvc_check": "unchecked",
"exp_month": 7,
"exp_year": 2019,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"last4": "0005",
"name": null
},
"client_ip": "127.0.0.1",
"type": "card",
"used": false
}
Number | Description |
---|---|
6200000000000005
|
Debit card. |
6200160000000007
|
Credit card. |
62001400000009
|
Card with a 14 digit number. |
620015000000008
|
Card with a 15 digit number. |
62001700000000004
|
Card with a 17 digit number. |
620018000000000005
|
Card with a 18 digit number. |
6200190000000000000
|
Card with a 19 digit number. |
6200160000000000
|
Valid card that fails luhn check. |
6200010000000004
|
Invalid card. |
6200160000000015
|
Charge is declined with an insufficient_funds code. |
6200160000000023
|
Charge is declined with a card_not_supported code. |
6200160000000031
|
Charge is declined with a card_expired code. |
6200160000000049
|
Charge succeeds but refunding a captured charge fails with a card_expired code. |
4242424242424242
|
Visa Card. |
You can use webhooks to be notified about events that happen in your Bongloy account. This mechanism is especially useful for services that are not directly responsible for making an API request, but still need to know the response from that request. Webhooks are necessary only for behind the scenes transactions. Most Bongloy requests (e.g. creating charges or creating refunds) happen synchronously and don't require webhooks for verification.
When the event occurs, Bongloy creates an Event
object which contains
the relevant information about what just happened, including the type of event
and the data associated with that event. Bongloy then sends the Event object,
via an HTTP POST request, to any endpoint URLs that you have createdin your account's
Webhook endpoints page.
{
"id": "3ddc184a-42c6-422e-9d39-8978d38afaa0",
"object": "event",
"created": 1549084295,
"livemode": false,
"data": {
"object": {
"id": "ecc28a2c-07d5-4504-b514-3a0ad1571cd0",
"paid": true,
"amount": 500,
"object": "charge",
"source": {
"id": "96db6b0c-102e-435d-8ef9-32cbe234a5cf",
"name": null,
"brand": "UnionPay",
"last4": "0005",
"object": "card",
"country": null,
"created": 1549084204,
"customer": null,
"exp_year": 2019,
"livemode": false,
"cvc_check": "unchecked",
"exp_month": 12,
"address_zip": null,
"fingerprint": "2c3f7ea106bccd749b5e97983ea18c2627935fe7b12662397187580e3957058d",
"address_city": null,
"address_line1": null,
"address_line2": null,
"address_state": null,
"address_country": null,
"address_zip_check": "unchecked",
"address_line1_check": "unchecked"
},
"status": "succeeded",
"created": 1549084291,
"dispute": null,
"refunds": {
"url": "/v1/charges/ecc28a2c-07d5-4504-b514-3a0ad1571cd0/refunds",
"data": [],
"object": "list",
"has_more": false
},
"captured": true,
"currency": "USD",
"customer": null,
"livemode": false,
"metadata": {},
"refunded": false,
"description": "Test live charge",
"failure_code": null,
"amount_refunded": 0,
"failure_message": null,
"balance_transaction": "272f810d-5df2-4a18-87a7-59082bc82564",
"statement_descriptor": null
}
},
"type": "charge.succeeded"
}
Webhooks are configured in theDashboard's Webhook endpoints section. Click on the New button and fill in URL for the endpoint.
Creating a webhook endpoint on your server is no different from creating any page on your website. With PHP, you might create a new .php file on your server; with a framework like Sinatra, you would add a new route with the desired URL.
Webhook data is sent as JSON in the POST request body. The full event details are included and can be used directly, after parsing the JSON into an Event object.
require 'json'
# Using Sinatra
post '/my/webhook/url' do
# Retrieve the request's body and parse it as JSON:
event_json = JSON.parse(request.body.read)
# Do something with event_json
status 200
end
If you're using Rails, Django, or another web framework, your site might automatically check that every POST request contains a CSRF token. This is an important security feature that helps protect you and your users from cross-site request forgery attempts. However, this security measure might also prevent your site from processing legitimate webhooks. If so, you might need to exempt the webhooks route from CSRF protection.
If you use an HTTPS URL for your webhook endpoint, Bongloy will validate that the connection to your server is secure before sending your webhook data. For this to work, your server must be correctly configured to support HTTPS with a valid server certificate.
To acknowledge receipt of a webhook, your endpoint should return a 2xx
HTTP status code. All response codes outside of this range, including 3xx
codes, will indicate to Bongloy that you did not receive the webhook. This means that a URL redirection or a "Not Modified" response will be treated as a failure. Bongloy will ignore any other information returned in the request headers or request body.
In case of failure, Bongloy will attempt to deliver your webhooks for up to five days with an exponential back off. Webhooks cannot be manually retried after this time.
Bongloy signs the webhook events it sends to your endpoints. We do this by including a signature in each event's Bongloy-Signature
header. This allows you to validate that the events were sent by Bongloy, not by a third party. Because Bongloy's API is compatible with Stripe's API you can verify signatures using Stripe's official libraries. You can also verify signatures manually using your own solution.
We recommend using one of Stripe libraries to verify signatures. You perform the verification by providing the event payload, the Bongloy-Signature
header, and the endpoint's secret. If verification fails, Stripe library returns an error. Here's an example of how to verify a signature using Stripe's offical Ruby library.
# Verifying a Webhook signature in Ruby
# You can find your endpoint's signing secret in your webhook settings page
webhook_signing_secret = 'ZeNerJt...'
payload = request.body.read
bongloy_signature = request.env['HTTP_BONGLOY_SIGNATURE']
# if the signature is invalid a Stripe::SignatureVerificationError will be raised
event = Stripe::Webhook.construct_event(payload, bongloy_signature, webhook_signing_secret)
A replay attack is when an attacker intercepts a valid payload and its signature, then re-transmits them. To mitigate such attacks, Bongloy includes a timestamp in the Bongloy-Signature header. Because this timestamp is part of the signed payload, it is also verified by the signature, so an attacker cannot change the timestamp without invalidating the signature. If the signature is valid but the timestamp is too old, you can have your application reject the payload.
Stripe's official libraries have a default tolerance of five minutes between the timestamp and the current time. You can change this tolerance by providing an additional parameter when verifying signatures. We recommend that you use Network Time Protocol (NTP) to ensure that your server's clock is accurate and synchronizes with the time on Bongloy's servers.
Bongloy generates the timestamp and signature each time we send an event to your endpoint.
If Bongloy retries an event (e.g., your endpoint previously replied with a non-2xx
status code), then we generate a new signature and timestamp for the new delivery attempt.
Although we recommend using Stripe's official libraries to verify webhook event signatures, you can use the following steps to create a custom solution.
The Bongloy-Signature
header contains a timestamp and signature. The timestamp is prefixed by t=
, and the signature is prefixed by v1=
. Here's an example:
"Bongloy-Signature": "t=1548737520, v1=e9094db9be3d8957e973471936b7ec41c82a24582f9d4751f57427430f47ce62"
Split the header, using the ,
character as the separator, to get a list of elements. Then split each element, using the =
character as the separator, to get a prefix and value pair.
The value for the prefix t
corresponds to the timestamp, and the value for the prefix v1
corresponds to the signature. You can discard all other elements.
signed_payload
can be constructed by concatenating:
.
Compute a HMAC with the SHA256 hash function. Use the endpoint's signing secret as the key, and use the signed_payload string as the message.
Compare the signature in the header to the expected signature. If a signature matches, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.
To protect against timing attacks, use constant-time string comparison to compare the expected signature to each of the received signatures.
Bongloy has been audited by a PCI-certified auditor and is certified to PCI Service Provider Level 1. This is the most stringent level of certification available in the payments industry. To accomplish this, we make use of best-in-class security tools and practices to maintain a high level of security at Bongloy.
Bongloy forces HTTPS for all services using TLS (SSL), including our public website and the Dashboard.
We use HSTS to ensure browsers interact with Bongloy only over HTTPS. Bongloy is also on the HSTS preloaded lists for both Google Chrome and Mozilla Firefox.
Below is a list of unofficial open source sample applications that work with Bongloy. If you would like your application listed below please contact us.
Application | Author(s) |
---|---|
Ruby Demo | Multiple |
Laravel Demo | Khom Sovon |
iOS Demo | Khom Sovon |