Developer APIs

Introduction

We have two different types of APIs, Apex and Rest.

What's the difference between the Apex and REST APIs?

REST API

Provides you an HTTP endpoint. Sending your data (which can be CC tokens obtained from Stripe, Transaction data, etc.) and receive a JSON response.

The objects are recorded in Salesforce, and it's your responsibility to process and handle the results on the client side. You can use the REST API in any environment where you can make HTTP calls (website, mobile app, outer space).

Apex API

It is a global Apex class, which you can access in your Salesforce Org or a Community. You can initialize Blackthorn | Payments entities (like Stripe Customer, Payment Methods and Transactions) and do actions (like send data to Stripe, update, capture, authorize, delete, etc).
You can integrate these actions into your custom Apex code, and it is your responsibility to handle the customer data.


Use Cases

  • Apex API: Visualforce website form
  • Apex API: Salesforce Community
  • Apex API: Your Salesforce internal app.
  • REST API: Non-Visualforce website form
  • REST API: Non-Salesforce custom portal
  • REST API: Mobile (Native or Hybrid) Application

Business Applications

Payment Form:

  • Create and validate a Payment Method (credit/debit/ACH), create and capture (charge) for a Transaction, display success and failure messages to the user.

Payment Method Management from a Community or Custom Portal:

  • Display "cards on file'"(or ACH accounts), allow users to create new cards, update cards, and delete cards.

Historical and Future Transactions:

  • Display all prior or future scheduled Transactions related to the user.

Portal or Community:

  • Because you already know who the authenticated user is (even from a single payment), you can create (or update) an Account and/or Contact, create or update an Opportunity, and manage the payment process.

View our FAQ for additional information.


Credit Card Verification

REST API

*Here's how you can tokenize a card with Stripe's javascript file (Stripe.js).
See https://stripe.com/docs/js

Apex API

  • The class returns the credit card status after committing it to Stripe. Data is pushed to the Apex back-end, which returns the result to the back-end, then you display it to the user.

Test credit card calls

  • Visit https://stripe.com/docs/testing for test codes. Make sure you have your Payment Gateway connected in Test Mode. You can do this by creating a Payment Gateway in test mode. Once you authenticate, your Payment Gateway will accept test cards (and only test cards).

Sample test code for unit tests that mock HTTP callouts

The below code example is for Stripe payment gateway. It includes valid Stripe JSON responses at the top.

public static final String customerResponse1 = '{"object": "customer", "created": 1443644461, "id": "cus_75160yvDQ32LzF", "livemode": false, "description": "Po Pa2", "email": null, "shipping": null, "delinquent": false, "metadata": {"sf_id":"a012800000vTBs0AAG"}, "subscriptions": {"object": "list", "total_count": 0, "has_more": false, "url": "/v1/customers/cus_75160yvDQ32LzF/subscriptions", "data": []}, "discount": null, "account_balance": 0, "currency": null, "sources": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/customers/cus_75160yvDQ32LzF/sources", "data": []}, "default_source": null}';
public static final String cardResponse1 = '{"id": "card_16qr4TDUbeQIIT0q7kzg9EAx", "object": "card", "last4": "4242", "brand": "Visa", "funding": "credit", "exp_month": 11, "exp_year": 2022, "fingerprint": "YFOyoTlT2Z8SsN5Y", "country": "US", "name": "Po Pa2", "address_line1": "100 E Colfax Ave", "address_line2": null, "address_city": "Denver", "address_state": "CO", "address_zip": "80202", "address_country": "US", "cvc_check": "pass", "address_line1_check": "unchecked", "address_zip_check": "unchecked", "tokenization_method": null, "dynamic_last4": null, "metadata": {"sf_id":"a012800000vTBs0AAG"}, "customer": "cus_75160yvDQ32LzF"}';
public static final String chargeResponse1 = '{"id":"ch_18JQ6QDXJoGaqeOAogZhnICo","object":"charge","amount":60000,"amount_refunded":0,"application_fee":"fee_8abJQqKs2NJc9p", "balance_transaction": { "id": "txn_18JQ6RDXJoGaqeOA7sk35j6w", "object": "balance_transaction", "amount": 60000, "available_on": 1465776000, "created": 1465228642, "currency": "usd", "description": null, "fee": 4803, "fee_details": [ { "amount": 1770, "application": null, "currency": "usd", "description": "Stripe processing fees", "type": "stripe_fee" }, { "amount": 3033, "application": "ca_7LBiXFKPurDHBtWP8vwphWEGoM4nMPB9", "currency": "usd", "description": "payment360 application fee", "type": "application_fee" } ], "net": 55197, "source": "ch_18JQ6QDXJoGaqeOAogZhnICo", "sourced_transfers": { "object": "list", "data": [], "has_more": false, "total_count": 0, "url": "/v1/transfers?source_transaction=ch_18JQ6QDXJoGaqeOAogZhnICo" }, "status": "pending", "type": "charge" }, "captured": true, "created": 1465228642, "currency": "usd", "customer": "cus_8ZXuXVhocCqMmQ", "description": null, "destination": null, "dispute": null, "failure_code": null, "failure_message": null, "fraud_details": {}, "invoice": null, "livemode": false, "metadata": {"sf_id":"a012800000vTBs0AAG"}, "order": null, "paid": true, "receipt_email": null, "receipt_number": null, "refunded": false, "refunds": { "object": "list", "data": [], "has_more": false, "total_count": 0, "url": "/v1/charges/ch_18JQ6QDXJoGaqeOAogZhnICo/refunds" }, "shipping": null, "source": { "id": "card_18IOocDXJoGaqeOAyOMR05ot", "object": "card", "address_city": null, "address_country": null, "address_line1": null, "address_line1_check": null, "address_line2": null, "address_state": null, "address_zip": null, "address_zip_check": null, "brand": "Visa", "country": "US", "customer": "cus_8ZXuXVhocCqMmQ", "cvc_check": null, "dynamic_last4": null, "exp_month": 11, "exp_year": 2019, "fingerprint": "X12JkaPTJYulTjMB", "funding": "credit", "last4": "4242", "metadata": {}, "name": "adsa dsada", "tokenization_method": null }, "source_transfer": null, "statement_descriptor": null, "status": "succeeded"}';

@IsTest
static void register_new_customer_and_multiple_pm_and_charge_multiple_transaction_happy1() {
    bt_StripeTest bt = new bt_StripeTest();
    bt.insertPaymentGateway(true);
    bt_StripeTest_HTTPMock mock = new bt_StripeTest_HTTPMock();
    mock.setBody(customerResponse1);
    mock.setBody(cardResponse1);
    mock.setBody(chargeResponse1);
    Test.setMock(HttpCalloutMock.class, mock);
    Test.startTest();
    P360_API_v1.Customer cust = bt_StripeTest.createAPICustomer(bt.pg.Id);
    cust.registerCustomer();
    P360_API_v1.PM pm = bt_StripeTest.createAPIPM(bt.pg.Id, cust);
    pm.registerPM();
    P360_API_v1.Tra tra = bt_StripeTest.createAPITra(bt.pg.Id, pm1);
    tra.capture();
    P360_API_v1.commitWork();
    Test.stopTest();
}

Unit Tests with our Web Services

You'll likely run into issues with unit tests. We're working on a more comprehensive method to solution this, but for now, please use:

bt_stripe__Stripe_Settings__c settings = bt_stripe__Stripe_Settings__c.getOrgDefaults();
settings.bt_stripe__Disable_All_Triggers__c = true;
upsert settings;

This will stop any callouts being made on Payment Method insertion and your unit tests will go through.


Creating Triggers with Payments objects

Blackthorn | Payments does HTTP callouts to the Stripe API endpoint.

A callout can be started in several ways, including:

  • Button pressed on the standard layout
  • Lightning Virtual Terminal
  • Batch processing (daily automatic payment collection)
  • REST API (incoming calls)
  • Invocable method started a Transaction processing
  • APEX API

This has several consequences:

  • Before a callout DML operations are not allowed
  • Before callouts, no asynchronous apex is allowed (batch, future)
  • Before callouts, no emails are allowed
  • These HTTP callouts count towards the HTTP callout limits (callout numbers and cumulative timeout)

Best practices

Apex API

Payments Apex API takes care of the DML operations; all you need to do is to run a commit() method when you finished your business with the provided Customer, PM and Transaction objects. However, keep in mind that Apex API makes HTTP callouts, so the limitations listed above apply (no DML statements, asynchronous Apex...) before the commit() method.

Triggers

Your triggers can interact with Blackthorn | Payments app objects in two ways.

  1. Listening to Payments Objects

You can bundle your triggers to insert / update / delete operations on Payments objects. Some of the most common use cases are:

Bundling a trigger to an insert of a Payment Method / Customer

Always look for the Stripe Id fields on the objects. A Customer / PM is inserted fully when there is a Stripe Id in the database.
When this Id is updated, there was a HTTP callout _before; so keep in mind that you are in this context._

Bundling a trigger to a Transaction

When inserting an Open status Transaction, you are safe, because there are no callouts. Callouts happen when a Transaction is processed. When it is successfully processed, the Transaction Status and Payment Status are changed and a Transaction Id is added.
Before this, an HTTP callout happened.

There is a use case when a user captures a Transaction using the "Capture" button, it fires a trigger which starts the processing asynchronously (in future). This means that you should not start other future operations from triggers bundled to Transaction status / id changes; or if you are doing so, always check your context, and start a future method only if you are in synchronous context.

  1. Your triggers start Transaction processing

If you want to interact with Payments objects, always use the provided APEX API. It cannot process Transactions in a trigger context because HTTP callouts are not allowed.
Move all your Transaction processing operations to future context.

REST API

Incoming REST API calls can create or process Payments objects. If you are using REST API and bundling triggers to Payments objects, keep in mind that the REST API user has other access rights than a regular Salesforce user.


Troubleshooting/FAQ

If you run into any errors with our REST API, open up Developer Tools in your browser, and recreate your scenario. There is an Error Message field under response that should provide insight into your issue.

If you a received an error or have a question, please view our API Troubleshooting/FAQ.
If you still have API questions, please contact Blackthorn Support. We're happy to help!



Did this page help you?