Skip to main content

Merchant Help

 

Affirm Merchant Help

VirtualCard Server-Side Integration

 

Overview

Integration Points
  • Checkout flow
    • Add new Affirm payment method selector
       
  • Generate checkout session and initiate checkout
    • Write code to populate checkout_data and generate checkout session token on the back-end
    • If checkout data is valid:
      • Pass checkout_session_token to the front-end and initiate checkout.
    • If checkout data is invalid:
      • Pass error 'message' along to the front-end, and optionally highlight the field that's causing the error.
         
  • Order confirmation
    • Write success callback function to pass the returned checkout_session_token to the back-end
    • Write server-side script to request card details using the checkout_session_token
    • Populate card fields with the card details returned server-side
       
  • Order management system
    • Flag orders paid using Affirm as such, so it can be distinguished from other orders paid with a card 
User Flow

  1. User selects Affirm payment method during checkout
  2. User submits checkout
  3. Merchant submits checkout object JSON to /checkout/session endpoint and generates checkout_session_token
  4. Merchant stores returned checkout_session_token and passes to front-end
  5. Merchant populates 'affirm.checkout.open_vcn({ checkout_session_token })' object
  6. Merchant calls 'affirm.checkout.open_vcn()' function
  7. Affirm checkout pop-up window displays
  8. User logs in or creates an account with Affirm
  9. User selects loan terms
  10. User confirms loan terms
  11. Success callback is triggered
  12. Merchant stores card_token string
  13. Merchant calls Affirm /card/ API endpoint with card_token to retrieve card details
  14. Merchant parses returned card details
  15. Merchant populates card form fields or submits card auth request on back-end
  16. Merchant submits checkout page
  17. Merchant sends card authorization hold request via their payment gateway
  18. Merchant waits for success response
  19. Merchant redirects user to order confirmation page
  20. Order is complete

 

Merchant account setup

How to access your Affirm merchant account credentials.
Google Account

You can sign into the Affirm Dashboard using Google, or using your email and password.

  • If you'd like to use the Google sign-in option, and your work email address isn't associated with a Google account, you can do so here: Sign up without Gmail
  • If your company uses Gmail, or if you already have a Google account, you can select your work account after clicking the Google sign-in button.

Go to the Merchant Dashboard

You can access the sandbox environment Merchant Dashboard here:

https://sandbox.affirm.com/dashboard

Sign in with your Google account. If you aren't able to login, or receive a Internal Server Error, you may not have access to this dashboard or the dashboard may not be enabled. Please contact merchanthelp@affirm.com to restore your access.

Affirm Merchant Sandbox Dashboard

  1. Go to: https://sandbox.affirm.com/dashboard.
  2. Sign in with Google, or use your email and password.

Note: The work email address that you use to sign-in to the Affirm Dashboard must be granted access by your Dashboard's administrator, or your Affirm contact.

Need help accessing the Affirm Dashboard?

Retrieve Sandbox Keys

Once you are in the Merchant Dashboard, use the navigation bar on the left to access your API Keys. You will need the public key, private key, and financial product key that is displayed here.

  1. Hover over the profile icon area at the lower-left of the page.
    Screen Shot 2016-03-22 at 7.56.58 AM-2.png
  2. Click the API Keys link that appears.
    Screen Shot 2016-03-22 at 7.56.20 AM.png
  3. Copy the public, private, and financial product keys.


 

Generate Checkout Session Token

Using checkout session tokens

A checkout session token is generated server-side, so that the checkout initiation on the client-side does not involve any handling of sensitive customer information (PII).

Once a user's checkout data is altered, a new session token must be generated.

The checkout session token request can result in several possible errors, which should be handled by your server and then presented to the user on the front-end.

Request format

Method: POST
Authentication: Basic Auth, Base64 ASCII encoded public:private keypair
Body: JSON format checkout data

Response format

Body: JSON

Checkout data

{
  "merchant":{
    "name": "Your Customer-Facing Merchant Name"
   },
  "shipping":{
    "name":{
      "full":"John Doe"
    },
    "address":{
      "line1":"325 Pacific Ave",
      "city":"San Francisco",
      "state":"CA",
      "zipcode":"94112",
      "country":"USA"
    }
  },
  "billing":{
    "name":{
      "full":"John Doe"
    },
    "address":{
      "line1":"325 Pacific Ave",
      "city":"San Francisco",
      "state":"CA",
      "zipcode":"94112",
      "country":"USA"
    }
  },
  "items": [{
    "display_name":         "Awesome Pants",
    "sku":                  "ABC-123",
    "unit_price":           1999,
    "qty":                  3,
    "item_image_url":       "http://merchantsite.com/images/awesome-pants.jpg",
    "item_url":             "http://merchantsite.com/products/awesome-pants.html"
  }],

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

  "shipping_amount":        1000,
  "tax_amount":             500,
  "total":                  6997
}
 
merchant
optional object. If you have multiple sites operating under a single Affirm account, you can override the external company/brand name that the customer sees using 'name'. This affects all references to your company name in the Affirm UI. 
billing
optional object.  Customer contact information.
shipping
required object. Customer contact information.
items
required list. A list of item objects.
discounts
optional hash. A hash of coupon code to discount objects.
tax_amount
required integer. The total tax amount computed after all discounts have been applied; Defaults to 0.
shipping_amount
required integer. The total shipping amount; Defaults to 0.
total
required integer. The total amount of the checkout. This determines the total amount charged to the user.
metadata
optional object. A hash of keys to values for any metadata to be passed into checkout and stored.
order_id
optional string. Your internal order id. This is stored for your own future reference.

Error response format

{
  "field": "object.field", 
  "message": "Some customer facing message.", 
  "code": "invalid_field", 
  "type": "invalid_request",
  "status_code": 40x|50x
}
field
string. Specific arameter/field associated with the returned error.
message
string. User-facing error message to be displayed on the front-end.
code
enum. Error code associated with this type of error.
type
string. Generic issue description.
status_code
integer. HTTP status code result for this request.

Example request

curl https://sandbox.affirm.com/api/v2/checkout/session \
     --verbose \
     -X POST \
     -u "ARQBLCL7NAMBTZ7F:RkHBmVSP5ayC2rCUujwhArpGWPxpuTtv" \
     -H "Content-Type: application/json"\
     -d '{"merchant": {"name":"Your Customer Facing Merchant Name"},"items": [{"display_name": "Great product","item_url": "http://www.google.com","item_image_url": "","qty": 2,"sku": "ABC123","unit_price": 10000}],"shipping": {"address": {"city": "San Francisco","line1": "633 Folsom Street","state": "CA","zipcode": "94107"},"name":{"full":"Ben Mo"},"phone_number":"9253232323"},"billing": {"address": {"city": "San Francisco","line1": "633 Folsom Street","state": "CA","zipcode": "94107"},"email":"benmoo@gmail.com","name":{"full":"Ben Mo"},"phone_number":"9253232323"},"total": 10000}'

Example success response

 

{
  "checkout_session_token": "ABCBLCL7NAMBTZDZ"
  "created": "2016-04-05T15:37:44.286033Z"
}
checkout_session_token
string. This event is triggered when the user successfully completes the Affirm checkout flow. The event data contains the virtual card token. This token will then be subsequently exchanged for the virtual card details via server-side API.
created
timestamp. This event is triggere

 

Example error response

 

{
  "field": "billing.name", 
  "message": "Please verify your name.", 
  "code": "invalid_field", 
  "type": "invalid_request",
  "status_code": 400
}
field
string. Specific arameter/field associated with the returned error.
message
string. User-facing error message to be displayed on the front-end.
code
enum. Error code associated with this type of error.
type
string. Generic issue description.
status_code
integer. HTTP status code result for this request.

 

Error Response Fields 

Edit section

Field R/O/C Type Description
field R String Field containing an incorrect or invalid value.
message R String Friendly message that describes the issue.
code R String Short code referencing the specific error.
type R String Type of error being returned.
status_code R String HTTP Status Code that was returned.

Possible code values 

Edit section

The list below contains all of the possible code values that can be returned by Affirm.

auth-declined
Charge authorization hold declined.
capture-greater-instrument
Charges on this instrument cannot be captured for more than the authorization hold amount.
capture-unequal-instrument
Charges on this instrument cannot be captured for an amount unequal to authorization hold amount.
capture-voided
Cannot capture voided charge.
partial-capture-instrument
Charges on this instrument cannot be partially captured.
refund-exceeded
Max refund amount exceeded.
refund-uncaptured
Cannot refund a charge that has not been captured.
refund-voided
Cannot refund voided charge.
capture-declined
Charge capture declined.
capture-limit-exceeded
Max capture amount on charge exceeded.
expired-authorization
Cannot capture expired charge authorization hold.
refund-expired
Charges on this instrument must be refunded within N days of capture.
financial-product-invalid
Please provide a valid financial product key.
invalid_field
An input field resulted in invalid request.
public-api-key-not-specified
Please provide a public API key.
public-api-key-invalid
Please provide a valid public API key.
public-api-key-wrong-environment
Please provide a live public API key when not using the sandbox environment.
public-api-key-inactive
Please provide an active public API key.
api-key-pair-not-specified
Please provide a API key pair.
private-api-key-invalid
Please provide a valid private API key.
api-key-pair-wrong-environment
Please provide a live API key pair when not using the sandbox environment.
api-key-pair-inactive
Please provide an active API key pair.
not_found
The resource(s) specified in the request could not be found.

Possible type values 

Edit section

The list below contains all of the possible type values that can be returned by Affirm.

invalid-request
A generic error that indicates request inputs were invalid.
unauthorized
API keys were invalid.

Possible status_code values 

Edit section

The list below contains all of the possible status_code values that can be returned by Affirm.

400
Request fields resulted in an error.
401
Authorization was unsuccessful.
404
The requested resource(s) could not be found.
50x
An internal server issue resulted in an error.

 


 

Initiate Checkout

Embed Affirm's JS runtime code

<script>
  _affirm_config = {
    public_api_key:  "XXXXXXXXXXXXXXX",
    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>

Note: replace the 'public_api_key' value with your own public API key. The API key must match the Affirm-environment you're referencing ('sandbox' or 'live').

Once the Affirm JS is initialized, the affirm.checkout method is made available:

  • affirm.checkout.open_vcn() - Initiates the VCN checkout window and accepts the checkout data object as its parameter.

The Affirm environment that's used is determined by the Affirm script URL that's defined in the _affirm_config.script:

var _affirm_config = {
    public_api_key:  "XXXXXXXXXXXXXXX",
    script:          "https://cdn1-sandbox.affirm.com/js/v2/affirm.js"
  };

Checkout Object

You can define a separate checkout object to contain the top-level parameters for the open_vcn() method. This is where you define the name of the checkout_data object, success callback, and error callback.

affirm.checkout.open_vcn({

      success: function(card_token) {
         success_callback_function();
      }
      error: error_callback_function
      checkout_session_token: checkoutSessionToken
  });
success
required event. This event is triggered when the user successfully completes the Affirm checkout flow. The event data contains the virtual card token. This token will then be subsequently exchanged for the virtual card details via server-side API.
error
optional event. This event is triggered if the user is denied, or if they voluntarily cancel the Affirm checkout flow. The event data is generic, and only indicates that the checkout was canceled (even if they were actually denied).
checkout_session_token
required string. The checkout session token corresponds to checkout data submitted to the Affirm servers previously, which contains all the cart details, customer information, and metadata for the order.


 

Checkout Result

Once a user enters the Affirm checkout flow, there are two possible results of the checkout attempt: 'success' and 'error'. 

Success

  • User is approved and confirms the Affirm loan terms: 
    • Success callback is triggered
    • Card token is returned in the event data
    • Server-side script sends the card token to the Affirm Virtual Card API and receives back the card details in the response
    • Custom Javascript fills in the card form on your checkout page automatically

Error

  • User closes the window:
    • Error callback is triggered
    • 'reason: closed' is returned in the event data
    • You can display messaging to the user to 'select another payment method'
       
  • User is denied or uses the cancel icon:
    • Error callback is triggered
    • 'reason: canceled' is returned in the event data
    • You can display messaging to the user to 'select another payment method'
       
  • Pop-up fails to open:
    • Error callback is triggered
    • 'reason: popups_disabled' is returned in the event data
    • You can display instructions to the user to 'enable pop-ups or select another payment method'
Card Token

{
   callback_id:"0cd3bcb1-8592-4ebf-a8cd-08816fbe266a",
   card_token:"1L7Y0UV4IR8LIA9G",
   created:"2016-04-04T14:24:06.386576Z"
}
callback_id
string. Can be ignored, for Affirm internal use.
card_token
string.  The card token that these card details correspond to.
created
timestamp. Time when this card token was generated.

Success Callback

affirm.checkout.open_vcn({

      success: success_callback

  });

Callback trigger

The success callback is triggered when the user confirms their Affirm loan terms in the pop-up window and is returned back to the checkout page.

Event data

The event data you need is:

  • Card token

 

Error Callback

Error Callback

 

affirm.checkout.open_vcn({

      error: cancel_callback

  });

 Event data

{reason: "closed"}
{reason: "canceled"}
{reason: "popups_disabled"}

 

Callback trigger

The error callback is triggered when the user cancels their application, closes the window, or the window is prevented from opening

Event data

The event data you need to utilize is:

  • Reason
    • closed
      • When the window is closed using the native window toolbar.
    • canceled
      • When the cancel icon or return button is clicked.
    • popups_disabled
      • When we detect that the pop up was blocked.

Callback behavior

Typically, your callback function will have the following behavior:

  1. Read the reason 
  2. Display a message if the user has disabled popups

Example function

function cancel_callback(e) {
   if(e.reason === "popups_disabled"){
      window.alert("Please enable pop-ups to checkout with Affirm");
      }


 

Retrieve Card Details

Card details request format

GET /api/v2/checkout/<checkout_id>/checkout_instrument

This returns the virtual card details associated with the card_token that was passed in the request body. Once the card details are returned, the card can be authorized through your usual card gateway.

Card details request

 

curl https://sandbox.affirm.com/api/v2/checkout/<checkout_id>/checkout_instrument
     -u "(public_api_key):(private_api_key)"

 

Card details response object

{
   billing_address: Object,
   callback_id:"0cd3bcb1-8592-4ebf-a8cd-08816fbe266a",
   cardholder_name:"John James Doe",
   card_token:"1L7Y0UV4IR8LIA9G",
   created:"2016-04-04T14:24:06.386576Z",
   cvv:"123",
   expiration:"0719",
   id:"1L7Y0UV4IR8LIA9G",
   number:"41111111111111111"
}
billing address
object. This object can be ignored, as you will always be using the customer's billing (if provided) or shipping address.
callback_id
string. Can be ignored, for Affirm internal use.
cardholder_name
string. Can be ignored, since you will always be using the customer's name.
card_token
string.  The card token that these card details correspond to.
created
string. Timestamp of when the card was generated.
cvv
string. The CVV verification code for the card.
expiration
string. A four-digit expiration date in MMYY format.
id
string. Can be ignored, the transaction ID for this API event.
number
string. The debit card number. This can be set to your payment gateway's test card number when using Affirm's sandbox environment.

Example card details request

curl https://sandbox.affirm.com/api/v2/checkout/<checkout_id>/checkout_instrument
     -u "(public_api_key):(private_api_key)"

Example card details response

{
   billing_address: Object,
   callback_id:"0cd3bcb1-8592-4ebf-a8cd-08816fbe266a",
   cardholder_name:"John James Doe",
   card_token:"1L7Y0UV4IR8LIA9G",
   created:"2016-04-04T14:24:06.386576Z",
   cvv:"123",
   expiration:"0719",
   id:"1L7Y0UV4IR8LIA9G",
   number:"41111111111111111"
}


 

Charge Actions

All charge actions are done using your existing payment gateway and gift card processor. 

To redeem or reload the virtual gift card, simply use your payment gateway API and the virtual gift card number that was used at checkout. 

Do not attempt to interact directly with the Affirm API for charges that were created using virtual gift card number. All charge interactions must be done through the card network.

Furthermore, the state of the Affirm charge as it appears in the Merchant Dashboard will not always reflect the charge state on the card network. For example, a refunded charge may not show as refunded on Affirm's side for up to 24 hours. Please refer to our merchant resources for customer-facing teams to help explain the relationship between charge actions on the gift card network (processed by the merchant) and the charge state in Affirm's system (visible to the customer).


 

Example Code

Create checkout session
curl https://sandbox.affirm.com/api/v2/checkout/session \
     --verbose \
     -X POST \
     -u "ARQBLCL7NAMBTZ7F:RkHBmVSP5ayC2rCUujwhArpGWPxpuTtv" \
     -H "Content-Type: application/json"\
     -d '{"merchant": {"public_api_key":"ARQBLCL7NAMBTZ7F","user_cancel_url": "http://requestb.in/14h8g7c1","user_confirmation_url": "http://requestb.in/xdxxyyxd"},"items": [{"display_name": "Great product","item_url": "http://www.google.com","item_image_url": "","qty": 2,"sku": "ABC123","unit_price": 10000}],"shipping": {"address": {"city": "San Francisco","line1": "633 Folsom Street","state": "CA","zipcode": "94107"},"name":{"full":"Z"},"phone_number":"9253236612"},"billing": {"address": {"city": "San Francisco","line1": "633 Folsom Street","state": "CA","zipcode": "94107"},"email":"benmoo@gmail.com","name":{"full":"Z"},"phone_number":"9253236612"},"total": 10000}'
Retrieve card
curl https://sandbox.affirm.com/api/v2/card/
     -X POST
     -u "(public_api_key):(private_api_key)"
     -H "Content-Type: application/json"
     -d '{"card_token": "ARZBLCL7NAMBTZ2D"}' 


 

Settlement

Since all charges are captured through your existing card gateway, you will rely on the existing settlement reports that are generated by your card gateway to reconcile transactions.

Affirm will provide a monthly invoice so that any applicable merchant fees can be remitted, and a more detailed transaction-level spreadsheet will be provided to reconcile Affirm transactions.