New integrations

This guide walks you through integration the full-stack Affirm integration along with Affirm Connect.

1. Add Affirm.js

Add the Affirm.js embed code to the head of your global page template.

<!-- Affirm -->
<script>
 _affirm_config = {
   public_api_key:  "YOUR_PUBLIC_KEY",
   script:          "https://cdn1-sandbox.affirm.com/js/v2/affirm.js"
 };
 (function(l,g,m,e,a,f,b){var d,c=l[m]||{},h=document.createElement(f),n=document.getElementsByTagName(f)[0],k=function(a,b,c){return function(){a[b]._.push([c,arguments])}};c[e]=k(c,e,"set");d=c[e];c[a]={};c[a]._=[];d._=[];c[a][b]=k(c,a,b);a=0;for(b="set add save post open empty reset on off trigger ready setProduct".split(" ");a<b.length;a++)d[b[a]]=k(c,e,b[a]);a=0;for(b=["get","token","url","items"];a<b.length;a++)d[b[a]]=function(){};h.async=!0;h.src=g[f];n.parentNode.insertBefore(h,n);delete g[f];d(g);l[m]=c})(window,_affirm_config,"affirm","checkout","ui","script","ready");
// Use your live public API Key and https://cdn1.affirm.com/js/v2/affirm.js script to point to Affirm production environment.
</script>
<!-- End Affirm -->

Be sure to use your public API key from the sandbox merchant dashboard for public_api_key.

📘

  • Be sure to use your public API key from the sandbox merchant dashboard for public_api_key.
  • Your global page template is the only place where you need this embed code.

2. Initiate a checkout

Checkout creation is the process in which a customer uses Affirm to pay for a purchase in your app.

Create a checkout object

Call affirm.checkout.open() to create the checkout object and send it to our Checkout API.

Set the exchange_lease_enabled field

Set the exchange_lease_enabled field to true on the Merchant object.

Set the leasable field

Set a leasable field for each Item object within the items array. Set the value to false if the merchandise cannot be leased (e.g. gift cards, warranties), and true if it is eligible to be leased.

Check the discount object

Check that all discounts are being added to the discount object, the Katapult checkout will not be triggered if the line item totals do not match the order total.

affirm.checkout.open({
      "merchant": {
        "user_confirmation_url":    "https://merchantsite.com/confirm",
        "user_cancel_url":          "https://merchantsite.com/cancel",
        "user_confirmation_url_action": "POST",
        "name": "Your Customer-Facing Merchant Name",
        "exchange_lease_enabled": true, 
      },
      "shipping":{
        "name":{
          "first":"Joe",
          "last":"Doe"
        },
        "address":{
          "line1":"633 Folsom St",
          "line2":"Floor 7",
          "city":"San Francisco",
          "state":"CA",
          "zipcode":"94107",
          "country":"USA"
        },
        "phone_number": "4153334567",
        "email": "[email protected]"
      },
      "billing":{
        "name":{
          "first":"Joe",
          "last":"Doe"
        },
        "address":{
          "line1":"633 Folsom St",
          "line2":"Floor 7",
          "city":"San Francisco",
          "state":"CA",
          "zipcode":"94107",
          "country":"USA"
        },
        "phone_number": "4153334567",
        "email": "[email protected]"
      },
      "items": [{
        "display_name":         "Awesome Pants",
        "unit_price":           1999,
        "qty":                  3,
        "item_image_url":       "http://merchantsite.com/images/awesome-pants.jpg",
        "item_url":             "http://merchantsite.com/products/awesome-pants.html",
        "leasable": true,
         "qty": 1,
         "sku": "ABC-123",
         "unit_price": 1999
        ]
      }
   ],
      "discounts":{
         "RETURN5":{
            "discount_amount":500,
            "discount_display_name":"Returning customer 5% discount"
        },
        "PRESDAY10":{
            "discount_amount":1000,
            "discount_display_name":"President's Day 10% off"
      }
   },
   "metadata":{
      "shipping_type":"UPS Ground",
   },
   "order_id":"JKLMO4321",
   "currency":"USD",  
   "financing_program":"flyus_3z6r12r",
   "shipping_amount":1000,
   "tax_amount":500,
   "total":100000
})

3. Authorization

Once you initiate the checkout object and the customer confirms their loan, we send an HTTP request with the checkout_token to the user_confirmation_url you defined in the checkout object. Next, you'll authorize the transaction using the checkout token sent to you. 

Receive the checkout token

To receive the checkout token, add server-side scripting that reads the HTTP request on your page. You can use any scripting language, such as PHP, ASP, Perl, Ruby, etc. If you need assistance, please contact [email protected].

<?
php $checkout_token = $_REQUEST['checkout_token'];
        
//These are sandbox credentials
// $public_key = "ARQBLCL7NAMBTZ7F"; 
// $private_key = "RkHBmVSP5ayC2rCUujwhArpGWPxpuTtv";
//This is the sandbox API URL
// $url = "https://sandbox.affirm.com/api/v2/charges/";

$data = array("checkout_token" => $checkout_token);
$json = json_encode($data);
$header = array('Content-Type: application/json','Content-Length: ' . strlen($json));

$keypair = $public_key . ":" . $private_key;

$curl = curl_init();

curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);                                                                     
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_USERPWD, $keypair);
curl_setopt($curl, CURLOPT_POSTFIELDS, $json);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);

$response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

curl_close($curl);

http_response_code($status);
echo $response;
?>
** 
 * Creating and Authorizing a Charge Request
 * To create and authorize a charge you will need to use the checkout_token that was POSTed to the user_confirmation_url. 
 * The response is a newly created JSON charge object, which is identified by its id field. This id will be used as the charge_id parameter in subsequent requests.
 * Upon receiving an authorized charge, you should check that the charge object corresponds to a valid order in your system. 
 * If it is valid, you may process the order and capture the charge. Otherwise, you should void the charge.
 */

// Required Fields
String apiVersion = "https://sandbox.affirm.com"; // Replace https://sandbox.affirm.com with https://api.affirm.com when ready to go live
String checkoutToken = ""; // The checkout_token that was POSTed to the user_confirmation_url after checkout; expires after 1 hour
String publicAPI = ""; // Public API Key available from Merchant Dashboard
String privateAPI = ""; // Private API Key available from Merchant Dashboard

try{
	// Open the connection to the Affirm API - replace sandbox.affirm.com with api.affirm.com when ready to go live
	URL url = new URL (apiVersion + "/api/v2/charges");
	HttpURLConnection httpsConnection = (HttpURLConnection) url.openConnection();
	
	// Set request properties
	httpsConnection.setRequestMethod("POST");
	httpsConnection.setDoOutput(true);
	httpsConnection.setRequestProperty("Content-Type", "application/json");
	httpsConnection.setRequestProperty("Authorization", "Basic " +
		Base64.getEncoder().encodeToString((publicAPI + ":" + privateAPI).getBytes())); // Base64 encode API keys for basic authentication
	
	// Write output as JSON object for POST
	String content = "{\"checkout_token\": \"" + checkoutToken + "\"}";
	OutputStreamWriter os = new OutputStreamWriter(httpsConnection.getOutputStream());
	os.write(content);	
	os.close();
	
	// Read API response; returned as JSON object
	InputStreamReader is = new InputStreamReader(httpsConnection.getInputStream());
	BufferedReader reader = new BufferedReader(is);
	StringBuilder result = new StringBuilder();
	String line;
	while((line = reader.readLine()) != null) {
	    result.append(line);
	}
	System.out.println(result.toString());
	
	// End API connection
	httpsConnection.disconnect();
}		
catch(Exception e){e.printStackTrace();}
using System;
using System.Web.UI;
using System.Net;
using System.IO;
using System.Text;
using System.Web.Script.Serialization;
using System.Web;
using System.Collections.Generic;

public partial class AuthRequest : Page
{
    ///Run when the page loads
    protected void Page_Load(object sender, EventArgs e)
    {
        ///Read the checkout_token from the POST request form
        string checkout_token = Request["checkout_token"];
        
        ///Auth POST request
        try {
            ///Create WebRequest instance
            HttpWebRequest httpWReq = (HttpWebRequest)WebRequest.Create("https://sandbox.affirm.com/api/v2/charges/");
            ///Define POST data
            Encoding encoding = new UTF8Encoding();
            string postData = "{\"checkout_token\":\""+checkout_token+"\"}";
            string apiKeys = "LSXKYTOB4Z3ZLLY4:0TDqgxXr5ZN0GsOY27Vw0WUM2Fzul9ix";
            byte[] data = encoding.GetBytes(postData);
            ///Configure POST request
            httpWReq.ProtocolVersion = HttpVersion.Version11;
            httpWReq.Method = "POST";
            httpWReq.ContentType = "application/json";
            httpWReq.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(encoding.GetBytes(apiKeys)));
            httpWReq.ContentLength = data.Length;
            ///Stream request
            Stream stream = httpWReq.GetRequestStream();
            stream.Write(data, 0, data.Length);
            stream.Close();
            ///Stream response
            HttpWebResponse response = (HttpWebResponse)httpWReq.GetResponse();
            StreamReader reader = new StreamReader(response.GetResponseStream());
            string responseText = reader.ReadToEnd();
            ///Output response to page container
            container.InnerHtml = responseText;
        }

        ///Catch exceptions
        catch (WebException exception){
            using (var stream = exception.Response.GetResponseStream()) {
                using (var reader = new StreamReader(stream)) {
                    string message = reader.ReadToEnd();
                    container.InnerHtml = message;
                }
            }
        }
    }
}

Trigger and test the checkout process

📘

When testing the checkout process, enter 1234 as your verification code as we don't send text messages from our sandbox.

While developing and testing in our sandbox, step through the checkout process in your browser to trigger the HTTP request with the checkout token.

Follow these steps to receive the checkout token:

  1. Initiate checkout to access the Affirm account creation screen.
  2. If you have an existing account, click Sign In.
  3. If you don't have an existing account, create one with the following:
    • Any first and last name
    • An email address with a valid format
    • A valid US cell phone number (you do not need access to this number) that you will use in all subsequent checkout attempts
    • A birth date older than 18 years old
    • Any four digits
  4. Enter **1234** for the verification code and click VERIFY CODE.
  5. Complete checkout flow and click CONFIRM LOAN.
  6. Click next to confirm Loan Schedule.

How to test the Katapult flow

  1. Initiate checkout to access the Affirm account creation screen.
  2. If you have an existing account, click Sign In.
  3. If you don't have an existing account, create one with the following:
    • Any first and last name
    • An email address with a valid format
    • A birth date: Use the date 12/01/1981 to trigger an Affirm decline and handoff to Katapult's pre-approval. Note that another other birthdate above the age of 18 will trigger an Affirm approval.
    • Social security : Any four digits
  4. Enter **1234** for the verification code and click VERIFY CODE.
  5. Select Check out with Katapult.
  6. Click next to confirm Loan Schedule.
  7. Katapult Payment information:
    • Card Number: 4111 1111 1111 1111
    • Expiration: future date
    • CVV: 3 digit number
Katapult flow

🚧

Important

  • To successfully test Katapult flow in Affirm's sandbox environment, enter a new identity (name, phone number, address, etc.) every time you go through the checkout flow.
  • If you get declined once, you may continue to get Katapult declined due to browser cookie caching. We recommend clearing your browser cookies / cache (or use Incognito browser window) before each test.

How to test the Snap flow

  1. Enter any valid US Number.
  2. Use 1234 for the PIN.
  3. Enter a name and email address.
  4. Use 07-07-1977 as the birth date.
  5. Enter any 4 digits for the SSN.
  6. Enter an income less than $100,000.
  7. Enter any payment dates.
  8. Enter any 9 digits for the routing number, except do not use 0 as the final number.
  9. Enter any 6-10 digits for the bank account number.
  10. Review the lease and proceed to the order confirmation page.
Snap flow

Authorization process

After completing the checkout flow and receiving the checkout token, you would process an Authorization request. Authorizing generates a transaction_id that you'll use to reference the transaction moving forward. Note that a transaction is not visible in the Read response, nor in the merchant dashboard until you authorize it.

After processing the authorization and receiving a success (200) response with the authorized amount, your  user_confirmation_url page should:

  • Validate that authorized amount equals the order total
  • Redirect the customer to the order confirmation page or display an order confirmation message
  • Store the transaction_id
  • Mark the order payment as pending

If there is an error (non-200) response during authorization or the authorized amount does not equal the order total:

1. Notify the customer that the payment failed.
2. Redirect the customer to the payment method selection screen.

🚧

Important

There are backwards incompatible changes when upgrading from /charges to /transactions APIs. View the our Changelog for changes when upgrading from /charges to /transactions APIs


4. Create your order management functions

To manage the Affirm transactions through the various transaction states, integrate each of these actions into your order management system where you fulfill orders and process payments, refunds, and cancelations.


5. Add Affirm promotional messaging

Affirm promotional messaging components---monthly payment messaging and educational modals---show customers how they can use Affirm to finance their purchases. Properly placed promotional messaging helps drive increased AOV and conversion.

As noted earlier, a front-end developer can complete this step in parallel with the rest of the integration process. Adding Affirm promotional messaging is a required integration step, and you should complete it before testing your integration. Click here for information about adding Affirm promotional messaging.


6. Add the confirmation page function

When a customer completes their purchase, you can send their order and product information to Affirm for A/B testing, which will help you optimize your site. Send this information by adding the Confirmation Page function to your payment confirmation page. We only require orderId, total, productId, and quantity for A/B testing.

Click here for all the Confirmation Page function parameters.

affirm.analytics.trackOrderConfirmed({
    "paymentMethod": "Visa",
    "orderId": "T12345",
    "total": 3739
}, [{
    "productId": "SKU-1234",
    "quantity": 1
}, {
    "productId": "SKU-5678",
    "quantity": 1
}]);

Required function parameters

Order object

ParameterDesrciption
paymentMethodstringThe payment method chosen by the customer (e.g., Visa). Maximum 150 characters.
orderIdstringYour internal unique identifier representing the order. Maximum 500 characters.
totalintegerThe total amount of the transaction, including tax and shipping, stated in USD cents (e.g., $100 = 10000).

Product object

ParameterDescription
productIdstringYour internal unique identifier representing the product, such as the SKU or an internal database identifier. Maximum 500 characters.
quantityintegerThe quantity of the purchased product.

7. Test your integration

After completing your integration, do a thorough testing of both your front-end and back-end integration in our sandbox to ensure that both the user experience and your order management system work as expected. Click here for our recommended test plan with a downloadable checklist. However, you'll need to tailor your testing plan to your specific systems, processes, and integration.


8. Deploy to production

Coordinate testing with Affirm

Before deploying the Affirm integration to your production site, Affirm will need to test it in your development or staging environment connected to our live environment. Contact your Integration Consultant or [email protected] to coordinate this test.

Connect to the live Affirm environment

1. Retrieve your public and private API keys at https://affirm.com/dashboard/#/apikeys
2. Update the script parameter in the Affirm.js embed code to point to our live environment at https://cdn1.affirm.com
3. Replace the public_api_key parameter in the Affirm.js embed code with the public API key you just retrieved
4. Update all your API calls to use the base URL, https://api.affirm.com, and to use the public and private API keys you just retrieved

Deploy to production

After you've connected to our live environment and we've tested your integration, you're ready to deploy to your production environment and offer Affirm as a payment option to your customers.

Error handling

A pop-up window will display any errors generated by the checkout process. For example, if there's an invalid phone number error, the customer sees this message.

You can define a callback function when the pop-up window closes. However, the callback function won't relay any event data about the error message.

Here is an example of a callback function.

affirm.ui.ready(
    function() {
        affirm.ui.error.on("close", function(){
            console.log("Affirm modal closed");
        });
    }
);