Getting Started

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:

  1. Obtain your API keys
  2. Install an API library so your integration can interact with the Bongloy API
  3. Make a test API request to confirm everything is up and running

Step 1: Obtain your API Keys

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.

  • Publishable API keys are only for identifying your account with Bongloy, they aren't secret. In other words, they can safely be published in places like your Bongloy.js JavaScript code, or in an Android or iPhone app.
  • Secret API keys should be kept confidential and only stored on your own servers. Your account's secret API key can perform any API request to Bongloy without restriction.
Before creating live charges, you'll need to create a live account and fill out the merchant application form. Once your account is approved, you'll have access to your live API keys.

Step 2: Install an API library

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 ensure 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.

Ruby

# Gemfile
gem "stripe", github: "stripe/stripe-ruby"

# config/initializers/bongloy.rb
Bongloy = Stripe
Bongloy.api_base = "https://api.bongloy.com"

PHP

$ composer require stripe/stripe-php

<?php
  require_once('vendor/autoload.php');
  use Stripe As Bongloy;

  Bongloy\Stripe::$apiBase = "https://api.bongloy.com";
?>

Step 3: Make a test API request

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.

Ruby

# 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

<?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"
  ]);
?>

Collecting cardholder data

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:

  • Use Bongloy.js or Stripe's mobile SDK libraries to collect payment information, which is securely transmitted directly to Bongloy without it passing through your servers
  • Serve your payment pages securely using Transport Layer Security (TLS) so that they make use of HTTPS
  • Review and validate your account's PCI compliance annually

Bongloy.js

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.

Including Bongloy.js

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>

Setting your publishable key

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.

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);

Collecting card details

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
Card number as a string without any separators, e.g. '4242424242424242'
exp_month
Two digit number representing the card's expiration month, e.g. 3
exp_year
Four digit number representing the card's expiration year, e.g. 2019
cvc
Card security code as a string, e.g. '123'

The following fields are entirely optional. They cannot result in a token creation failing:

name
Cardholder's name
address_line1
Billing address line 1
address_line2
Billing address line 2
address_state
Billing address state
address_zip
Billing address zip as a string, e.g. '94301'
address_country
Billing address country

The third argument bongloyResponseHandler is a callback you provide to handle the response from Bongloy. It should do the following:

  • If the card information entered by the user returned an error, display it on the page.
  • If no errors were returned (i.e. a single-use token was created successfully), add the returned token to the payment form and submit the form to your server.

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": null,
    "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's Mobile Libraries

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.

iOS

Install and configure the SDK

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

Configure your Bongloy integration in your App Delegate

// 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
  }
}

Create a Bongloy API Client

// 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"

Create a Token

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...
    }
  })
}

Bongloy API Reference

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.

Authentication

You authenticate to the Bongloy API by providing one of your API keys in the request. You can view your API keys from the developer section of the dashboard. All API requests must be made over HTTPS. Calls made over plain HTTP will fail. You must authenticate for all requests.

Charges

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.

Create a new charge

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).

Authorization Parameters
key
Required. Your Secret API Key.
sk_test_abcde...
Request Parameters
amount
Required. A positive integer in the smallest currency unit (e.g 100 cents to charge $1.00) representing how much to charge the card. Also aliased as amount_cents
currency
Required. 3-letter ISO code for currency. e.g. USD
customer
Optional. Either a customer or card is required. The ID of an existing customer that will be charged in this request.
source
Optional. Either a source or customer is required. A payment source to be charged. If you also pass a customer ID, the source must be the ID of a source belonging to the customer. Otherwise, if you do not pass a customer ID, the source you provide must be a token, like the ones returned by Bongloy.js
description
Optional. Default is null
capture
Optional. Default is true. Whether or not to immediately capture the charge. When false, the charge issues an authorization (or pre-authorization), and will need to be captured later.
statement_descriptor
Optional. Extra information about a charge. This will appear on your customer's credit card statement. Limited to 22 characters, cannot use the greater than, less than, single quote or double-quote symbols (>, <, ', ")
Returns

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.

Example Request: Charging a Card

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"

Example Response

{
  "id": "f1cb560f-e0ac-454e-9bf1-2917bff4d978",
  "object": "charge",
  "created": 1535543359,
  "livemode": false,
  "amount": 10000,
  "amount_refunded": 0,
  "balance_transaction": "beeabc87-bbed-421d-91a8-c3983877b63c",
  "captured": true,
  "currency": "USD",
  "customer": null,
  "description": "Charge for 1 case of Singha at KTV",
  "dispute": null,
  "failure_code": null,
  "failure_message": null,
  "paid": true,
  "refunded": false,
  "refunds": {
    "has_more": false,
    "object": "list",
    "url": "/v1/charges/f1cb560f-e0ac-454e-9bf1-2917bff4d978/refunds",
    "data": [

    ]
  },
  "source": {
    "id": "f8430eb4-9f61-4e8b-a703-5b3312ddd840",
    "object": "card",
    "created": 1535543359,
    "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": "unchecked",
    "exp_month": 8,
    "exp_year": 2018,
    "fingerprint": null,
    "last4": "4242",
    "name": null
  },
  "statement_descriptor": "Singha",
  "status": "succeeded"
}

Retrieve an existing charge

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.

Authorization Parameters
key
Required. Your Secret API Key.
sk_test_abcde...
Request Parameters
id
Required. The id of the charge to be retrieved.
Returns

Returns a charge object if a valid id was provided, and returns an error otherwise.

Example Request

curl https://api.bongloy.com/v1/charges/f1cb560f-e0ac-454e-9bf1-2917bff4d978 \
-u sk_test_abcde...:

Example Response

{
  "id": "f1cb560f-e0ac-454e-9bf1-2917bff4d978",
  "object": "charge",
  "created": 1535543359,
  "livemode": false,
  "amount": 10000,
  "amount_refunded": 0,
  "balance_transaction": "beeabc87-bbed-421d-91a8-c3983877b63c",
  "captured": true,
  "currency": "USD",
  "customer": null,
  "description": "Charge for 1 case of Singha at KTV",
  "dispute": null,
  "failure_code": null,
  "failure_message": null,
  "paid": true,
  "refunded": false,
  "refunds": {
    "has_more": false,
    "object": "list",
    "url": "/v1/charges/f1cb560f-e0ac-454e-9bf1-2917bff4d978/refunds",
    "data": [

    ]
  },
  "source": {
    "id": "f8430eb4-9f61-4e8b-a703-5b3312ddd840",
    "object": "card",
    "created": 1535543359,
    "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": "unchecked",
    "exp_month": 8,
    "exp_year": 2018,
    "fingerprint": null,
    "last4": "4242",
    "name": null
  },
  "statement_descriptor": "Singha",
  "status": "succeeded"
}

Customers

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.

Create a new customer

Creates a customer object

Authorization Parameters
key
Required. Your Secret API Key.
sk_test_abcde...
Request Parameters
source
Optional. If supplied, it must be a token, like the ones returned by Bongloy.js
description
Optional.
email
Optional. Customer's email address. It's displayed alongside the customer in your dashboard and can be useful for searching and tracking.
Returns

Returns a customer object if the call succeeded. 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.

Example Request

To create a customer you first need to create a token that represents the customer's card. You can create a token using Bongloy.js

curl https://api.bongloy.com/v1/customers \
  -u sk_test_abcde...: \
  -d source=<token_id> \
  -d "description=Customer for jenny.rosen@example.com"

Example Response

{
  "id": "c82d526d-c8dd-4396-8852-be818fdc0b50",
  "object": "customer",
  "created": 1535544463,
  "livemode": false,
  "default_source": "49a5f3c7-f12c-49b6-a85d-c8a7053fbf39",
  "description": "Customer for jenny.rosen@example.com",
  "email": null,
  "sources": {
    "has_more": false,
    "object": "list",
    "url": "/v1/customers/c82d526d-c8dd-4396-8852-be818fdc0b50/sources",
    "data": [

    ]
  }
}

Retrieve an existing customer

Retrieves the details of an existing customer. You need only supply the unique customer identifier that was returned upon customer creation.

Authorization Parameters
key
Required. Your Secret API Key.
sk_test_abcde...
Request Parameters
id
Required. The id of the customer to be retrieved.
Returns

Returns a customer object if a valid id was provided. Returns a 404 otherwise.

Example Request

curl https://api.bongloy.com/v1/customers/c82d526d-c8dd-4396-8852-be818fdc0b50 \
  -u sk_test_abcde...:

Example Response

{
  "id": "c82d526d-c8dd-4396-8852-be818fdc0b50",
  "object": "customer",
  "created": 1535544463,
  "livemode": false,
  "default_source": "49a5f3c7-f12c-49b6-a85d-c8a7053fbf39",
  "description": "Customer for jenny.rosen@example.com",
  "email": null,
  "sources": {
    "has_more": false,
    "object": "list",
    "url": "/v1/customers/c82d526d-c8dd-4396-8852-be818fdc0b50/sources",
    "data": [

    ]
  }
}

Cards

You can store multiple cards on a customer in order to charge the customer later.

Create a new card

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. To change the default, you should update the customer to have a new default_source

Authorization Parameters
key
Required. Your Secret API Key.
sk_test_abcde...
Request Parameters
source
Required. It must be a token, like the ones returned by Bongloy.js
Returns

Returns the card object.

Example Request

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/c82d526d-c8dd-4396-8852-be818fdc0b50/sources \
  -u sk_test_abcde...: \
  -d source=<token_id>

Example Response

{
  "id": "47b239af-983b-42d7-b222-66e432f550fd",
  "object": "card",
  "created": 1535545089,
  "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": "c82d526d-c8dd-4396-8852-be818fdc0b50",
  "cvc_check": "unchecked",
  "exp_month": 8,
  "exp_year": 2018,
  "fingerprint": null,
  "last4": "4242",
  "name": null
}

Retrieve an existing card

Retrieves the details of an existing card for a customer.

Authorization Parameters
key
Required. Your Secret API Key.
sk_test_abcde...
Request Parameters
id
Required. The id of the card to be retrieved.
Returns

Returns the card object if a valid id was provided. Returns a 404 otherwise.

Example Request

curl https://api.bongloy.com/v1/customers/ccc526e2-4440-4c7d-80a5-0173d3bc6f1f/sources/47b239af-983b-42d7-b222-66e432f550fd \
  -u sk_test_abcde...:

Example Response

{
  "id": "47b239af-983b-42d7-b222-66e432f550fd",
  "object": "card",
  "created": 1535545089,
  "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": "ccc526e2-4440-4c7d-80a5-0173d3bc6f1f",
  "cvc_check": "unchecked",
  "exp_month": 8,
  "exp_year": 2018,
  "fingerprint": null,
  "last4": "4242",
  "name": null
}

List all Cards

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.

Authorization Parameters
key
Required. Your Secret API Key.
sk_test_abcde...
Request Parameters
customer
Required. The ID of the customer whose cards will be retrieved.
Returns

Returns a list of the cards stored on the customer.

Example Request

curl https://api.bongloy.com/v1/customers/ccc526e2-4440-4c7d-80a5-0173d3bc6f1f/sources \
  -u sk_test_abcde...:

Example Response

{
  "has_more": false,
  "object": "list",
  "url": "/v1/customers/ccc526e2-4440-4c7d-80a5-0173d3bc6f1f/sources",
  "data": [
    {
      "id": "16b1634f-e2b9-4455-8544-fa44ccc0118e",
      "object": "card",
      "created": 1535545335,
      "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": "ccc526e2-4440-4c7d-80a5-0173d3bc6f1f",
      "cvc_check": "unchecked",
      "exp_month": 8,
      "exp_year": 2019,
      "fingerprint": null,
      "last4": "5586",
      "name": null
    }
  ]
}

Delete a card

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.

Authorization Parameters
key
Required. Your Secret API Key.
sk_test_abcde...
Request Parameters
source
Required. It must be a token, like the ones returned by Bongloy.js
Returns

204

Example Request

curl https://api.bongloy.com/v1/customers/ccc526e2-4440-4c7d-80a5-0173d3bc6f1f/sources/47b239af-983b-42d7-b222-66e432f550fd \
  -u sk_test_abcde...: \
  -d source=<token_id> \
  -X DELETE

Example Response
204

Refunds

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. The fees you were originally charged are also refunded.

Create a new refund

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.

Authorization Parameters
key
Required. Your Secret API Key.
sk_test_abcde...
Request Parameters
charge
Required. The identifier of the charge to refund.
amount
Optional. Defaults to entire charge amount. A positive integer representing how much of this charge to refund. Can only refund up to the unrefunded amount remaining on the charge.
Returns

Returns the refund object if the refund succeeded. Returns an error if the charge has already been refunded or an invalid charge identifier was provided.

Example Request

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>

Example Response

{
  "id": "6cb88736-d034-42eb-8629-9135f4f0fd50",
  "object": "refund",
  "created": 1553077284,
  "amount": 10000,
  "balance_transaction": "89bbb4e7-ebfe-4913-9e37-c23b3a7571df",
  "charge": "1f05adb3-1e96-4147-9d67-9d0c8b412df8",
  "currency": "USD",
  "metadata": {},
  "status": "succeeded",
  "failure_balance_transaction": null
}

Retrieve an existing refund

Retrieves the details of an existing refund.

Authorization Parameters
key
Required. Your Secret API Key.
sk_test_abcde...
Request Parameters
refund_id
Required. The id of the refund to retrieve.
Returns

Returns a refund if a valid ID was provided. Returns an error otherwise.

Example Request

curl https://api.bongloy.com/v1/refunds/3f19df4e-49a1-4b40-b6d9-6923e1e11664 \
  -u sk_test_abcde...:

Example Response

{
  "id": "6cb88736-d034-42eb-8629-9135f4f0fd50",
  "object": "refund",
  "created": 1553077284,
  "amount": 10000,
  "balance_transaction": "89bbb4e7-ebfe-4913-9e37-c23b3a7571df",
  "charge": "1f05adb3-1e96-4147-9d67-9d0c8b412df8",
  "currency": "USD",
  "metadata": {},
  "status": "succeeded",
  "failure_balance_transaction": null
}

Test Cards

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.

Webhooks

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.

Events

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 created in 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": null,
        "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"
}

Configuring your Webhooks settings

Webhooks are configured in the Dashboard's Webhook endpoints section. Click on the New button and fill in URL for the endpoint.

Receiving a webhook notification

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

Receiving webhooks with a CSRF-protected server

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.

Receiving webhooks with a HTTPS server

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.

Responding to a Webhook

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.

Verifying a webhook

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.

Verifying signatures using Stripe's official libraries

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)

Preventing replay attacks

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.

Verifying signatures manually

Although we recommend using Stripe's official libraries to verify webhook event signatures, you can use the following steps to create a custom solution.

Step 1: Extract timestamp and signature from the header.

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.

Step 2: Prepare the signed_payload string

signed_payload can be constructed by concatenating:

  • The timestamp (as a string)
  • The character .
  • The actual JSON payload (i.e. the request's body)
  • Step 3: Determine the expected signature

    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.

    Step 4: Compare signatures

    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.

    Unofficial Sample Applications

    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