Quickstart
Create a session token
Your server must create a session token before your client app can initialize Forage Inline Checkout. Keep your Forage authentication token on your server and expose a backend route that your client app can call to request a session token.
A successful request to /session_token/ returns a temporary session token. Session tokens expire after 15 minutes, so create one shortly before rendering checkout.
Below is an example request and response with added context:
Server Request
curl --request POST \
--url https://api.sandbox.joinforage.app/api/session_token/ \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <authentication-token>' \
--header 'Merchant-Account: <merchant-id>' \
--header 'Content-Type: application/x-www-form-urlencoded'import requests
response = requests.post(
"https://api.sandbox.joinforage.app/api/session_token/",
headers={
"Accept": "application/json",
"Authorization": "Bearer <authentication-token>",
"Merchant-Account": "<merchant-id>",
"Content-Type": "application/x-www-form-urlencoded",
},
)
print(response.json())import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.sandbox.joinforage.app/api/session_token/"))
.header("Accept", "application/json")
.header("Authorization", "Bearer <authentication-token>")
.header("Merchant-Account", "<merchant-id>")
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());const response = await fetch(
"https://api.sandbox.joinforage.app/api/session_token/",
{
method: "POST",
headers: {
Accept: "application/json",
Authorization: "Bearer <authentication-token>",
"Merchant-Account": "<merchant-id>",
"Content-Type": "application/x-www-form-urlencoded",
},
}
);
const data = await response.json();
console.log(data);require 'net/http'
require 'json'
uri = URI("https://api.sandbox.joinforage.app/api/session_token/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.path)
request["Accept"] = "application/json"
request["Authorization"] = "Bearer <authentication-token>"
request["Merchant-Account"] = "<merchant-id>"
request["Content-Type"] = "application/x-www-form-urlencoded"
response = http.request(request)
puts JSON.parse(response.body)Required Headers:
Authorization: A Forage authentication token prefixed withBearer. Generate and store this token on your server; never expose it in client-side code.Merchant-Account: The unique merchant ID that Forage provides during onboarding. Use the same merchant ID when you instantiate Checkout.
Response
{
"token": "sandbox_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}token: Pass this value to thesessionTokenproperty when you instantiate Checkout in your client app.
Add Checkout in your app
Add the Forage Checkout SDK for your client platform:
npm install @forage/checkout-sdk// Package.swift
dependencies: [
.package(
url: "<Forage Checkout SDK package URL>",
from: "<version>"
)
]// build.gradle.kts
dependencies {
implementation("com.joinforage:checkout-sdk:<version>")
}Initialize Checkout using the SDK for your client platform. Pass the order details through config.data, along with the session token returned by your server and the merchant ID used to create it.
import { Checkout } from "@forage/checkout-sdk";
<Checkout
config={{
action: "checkout",
data: {
{
snapTotal: 25.99,
ebtCashTotal: 5.99,
remainingTotal: 10.99,
platformFee: 0.05,
productList: [
{
name: "Apple",
upc: "033383087375",
unitPrice: 1.99,
quantity: 3,
eligibility: "snap",
taxesCharged: 3.33,
taxesExempted: 0.00
},
{
name: "Vitamin C",
upc: "04126001300",
unitPrice: 12.99,
quantity: 1,
eligibility: "non_ebt",
taxesCharged: 1.83,
taxesExempted: 0.50
}
],
deliveryAddress: {
city: "Los Angeles",
country: "US",
line1: "4121 Santa Monica Blvd",
line2: "Unit 513",
zipcode: "90029",
state: "CA"
},
isDelivery: true,
supportedBenefits: [
"snap",
"ebt_cash",
"non_ebt"
],
customerId: "cus_AJ6yA7mRH34mJT"
},
},
onInit={(data) => {
// Send data.ref to your server for verification.
}}
onComplete={(data) => {
// Send data.ref to your server for verification, then update your UI.
}}
onCancel={(data) => {
// Send data.ref to your server for verification, then update your UI.
}}
}}
sessionToken="sandbox_..."
merchantId="abc123"
/>import ForageCheckoutSDK
let checkout = Checkout(
config: CheckoutConfig(
action: "checkout",
data: CheckoutData(
snapTotal: 25.99,
ebtCashTotal: 5.99,
remainingTotal: 10.99,
platformFee: 0.05,
productList: [
CheckoutProduct(
name: "Apple",
upc: "033383087375",
unitPrice: 1.99,
quantity: 3,
eligibility: "snap",
taxesCharged: 3.33,
taxesExempted: 0.00
),
CheckoutProduct(
name: "Vitamin C",
upc: "04126001300",
unitPrice: 12.99,
quantity: 1,
eligibility: "non_ebt",
taxesCharged: 1.83,
taxesExempted: 0.50
)
],
deliveryAddress: DeliveryAddress(
city: "Los Angeles",
country: "US",
line1: "4121 Santa Monica Blvd",
line2: "Unit 513",
zipcode: "90029",
state: "CA"
),
isDelivery: true,
supportedBenefits: ["snap", "ebt_cash", "non_ebt"],
customerID: "cus_AJ6yA7mRH34mJT"
),
onInit: { data in
// Send data.ref to your server for verification.
},
onComplete: { data in
// Send data.ref to your server for verification, then update your UI.
},
onCancel: { data in
// Send data.ref to your server for verification, then update your UI.
}
),
sessionToken: "sandbox_...",
merchantID: "abc123",
)import com.joinforage.checkout.Checkout
import com.joinforage.checkout.CheckoutAddress
import com.joinforage.checkout.CheckoutConfig
import com.joinforage.checkout.CheckoutData
import com.joinforage.checkout.CheckoutProduct
val checkout = Checkout(
config = CheckoutConfig(
action = "checkout",
data = CheckoutData(
snapTotal = 25.99,
ebtCashTotal = 5.99,
remainingTotal = 10.99,
platformFee = 0.05,
productList = listOf(
CheckoutProduct(
name = "Apple",
upc = "033383087375",
unitPrice = 1.99,
quantity = 3,
eligibility = "snap",
taxesCharged = 3.33,
taxesExempted = 0.00
),
CheckoutProduct(
name = "Vitamin C",
upc = "04126001300",
unitPrice = 12.99,
quantity = 1,
eligibility = "non_ebt",
taxesCharged = 1.83,
taxesExempted = 0.50
)
),
deliveryAddress = CheckoutAddress(
city = "Los Angeles",
country = "US",
line1 = "4121 Santa Monica Blvd",
line2 = "Unit 513",
zipcode = "90029",
state = "CA"
),
isDelivery = true,
supportedBenefits = listOf("snap", "ebt_cash", "non_ebt"),
customerId = "cus_AJ6yA7mRH34mJT"
),
onInit = { data ->
// Send data.ref to your server for verification.
},
onComplete = { data ->
// Send data.ref to your server for verification, then update your UI.
},
onCancel = { data ->
// Send data.ref to your server for verification, then update your UI.
}
),
sessionToken = "sandbox_...",
merchantId = "abc123",
)config.action: The Checkout operation to perform. Passcheckoutto start an inline checkout flow.config.data: The order details that Forage uses to create and process theOrder.sessionToken: The temporary token returned by your server's request to/session_token/.merchantId(merchantIDon iOS): The merchant ID used to create the session token.onInit: Called after the checkout session is created. The callback receives the createdOrderobject, consistent with the response fromPOST /sessions.onComplete: Called after the customer successfully completes checkout. The callback receives the completedOrderobject.onCancel: Called after checkout is canceled. The callback receives the canceledOrderobject, consistent with the response fromPOST /orders/{order_ref}/cancel/.
The properties in config.data correspond to the request body properties used to create an order. Web uses the API's snake_case field names; the native SDKs expose the same fields with platform-standard casing:
snapTotal: The portion of the order total that the customer can pay with SNAP.ebtCashTotal: The portion of the order total that the customer can pay with EBT Cash.remainingTotal: The portion of the order total that the customer must pay with a non-EBT payment method.platformFee: The percentage of each payment charged as a platform fee, when applicable.productList: The products included in the order, including their prices, quantities, eligibility, and tax details.deliveryAddress: The address where the order will be delivered or picked up. Required by FNS.isDelivery: Whether the order will be delivered or picked up. Required by FNS.supportedBenefits: The payment method types available during checkout.customerID(iOS) /customerId(Web and Android): Your identifier for the customer.
onInit response
onInit responseAfter the checkout session is created, Forage calls onInit with the created Order object:
{
"snap_total": 25.99,
"ebt_cash_total": 5.99,
"remaining_total": 10.99,
"platform_fee": 0.05,
"product_list": [
{
"name": "Apple",
"upc": "033383087375",
"unit_price": 1.99,
"quantity": 3,
"eligibility": "snap",
"taxes_charged": 3.33,
"taxes_exempted": 0.00
},
{
"name": "Vitamin C",
"upc": "04126001300",
"unit_price": 12.99,
"quantity": 1,
"eligibility": "non_ebt",
"taxes_charged": 1.83,
"taxes_exempted": 0.50
}
],
"delivery_address": {
"city": "Los Angeles",
"country": "US",
"line1": "4121 Santa Monica Blvd",
"line2": "Unit 513",
"zipcode": "90029",
"state": "CA"
},
"is_delivery": true,
"supported_benefits": [
"snap",
"ebt_cash",
"non_ebt"
],
"customer_id": "cus_AJ6yA7mRH34mJT",
"ref": "93410bcaff",
"status": "draft",
"payments": [],
"refunds": [],
"receipt": null
}ref: Store a reference to thisOrderobject for your records and send it to your server for verification.status: The current state of the order. A newly created order has a status ofdraft.
onComplete response
onComplete responseAfter the customer successfully completes checkout, Forage calls onComplete with the completed Order object:
{
"snap_total": 25.99,
"ebt_cash_total": 5.99,
"remaining_total": 10.99,
"platform_fee": 0.05,
"product_list": [
{
"name": "Apple",
"upc": "033383087375",
"unit_price": 1.99,
"quantity": 3,
"eligibility": "snap",
"taxes_charged": 3.33,
"taxes_exempted": 0.00
},
{
"name": "Vitamin C",
"upc": "04126001300",
"unit_price": 12.99,
"quantity": 1,
"eligibility": "non_ebt",
"taxes_charged": 1.83,
"taxes_exempted": 0.50
}
],
"delivery_address": {
"city": "Los Angeles",
"country": "US",
"line1": "4121 Santa Monica Blvd",
"line2": "Unit 513",
"zipcode": "90029",
"state": "CA"
},
"is_delivery": true,
"supported_benefits": [
"snap",
"ebt_cash",
"non_ebt"
],
"customer_id": "cus_AJ6yA7mRH34mJT",
"ref": "93410bcaff",
"status": "succeeded",
"payments": [],
"refunds": [],
"receipt": {
"ref_number": "93410bcaff",
"snap_amount": "25.99",
"ebt_cash_amount": "5.99",
"other_amount": "10.99",
"sales_tax_applied": "5.16",
"balance": {
"snap": "25.99",
"non_snap": "10.99",
"updated": "2021-06-16T00:11:50.000000Z-07:00"
},
"last_4": "3456",
"message": "Approved",
"transaction_type": "Purchase",
"created": "2021-06-16T00:11:50.000000Z-07:00"
}
}ref: Store a reference to thisOrderobject for your records and send it to your server for verification.status: The current state of the order. A successfully completed order has a status ofsucceeded.receipt: The transaction details required to build your receipt or confirmation screen.
onCancel response
onCancel responseIf the customer cancels checkout before the order is completed, Forage calls onCancel with the canceled Order object:
{
"snap_total": 25.99,
"ebt_cash_total": 5.99,
"remaining_total": 10.99,
"platform_fee": 0.05,
"product_list": [
{
"name": "Apple",
"upc": "033383087375",
"unit_price": 1.99,
"quantity": 3,
"eligibility": "snap",
"taxes_charged": 3.33,
"taxes_exempted": 0.00
},
{
"name": "Vitamin C",
"upc": "04126001300",
"unit_price": 12.99,
"quantity": 1,
"eligibility": "non_ebt",
"taxes_charged": 1.83,
"taxes_exempted": 0.50
}
],
"delivery_address": {
"city": "Los Angeles",
"country": "US",
"line1": "4121 Santa Monica Blvd",
"line2": "Unit 513",
"zipcode": "90029",
"state": "CA"
},
"is_delivery": true,
"supported_benefits": [
"snap",
"ebt_cash",
"non_ebt"
],
"customer_id": "cus_AJ6yA7mRH34mJT",
"ref": "93410bcaff",
"status": "canceled",
"payments": [],
"refunds": [],
"receipt": null
}ref: Store a reference to thisOrderobject for your records and send it to your server for verification.status: A canceled order has a status ofcanceled.
How to initialize Checkout with a saved payment method
If you recognize a customer, you can initialize Checkout with an EBT payment method that the customer saved during a previous checkout. Pass the payment method reference as ebt_payment_method on Web or ebtPaymentMethod on iOS and Android.
import { Checkout } from "@forage/checkout-sdk";
<Checkout
config={{
action: "checkout",
data: {
{
deliveryAddress: {
country: "US",
line1: "4121 Santa Monica Blvd",
city: "Los Angeles",
zipcode: "90029",
state: "CA"
},
productList: [],
isDelivery: true,
supportedBenefits: [
"snap",
"ebt_cash",
"non_ebt"
],
ebtPaymentMethod: "f629aa1bf3"
},
},
onInit={(data) => {
// Send data.ref to your server for verification.
}},
onComplete={(data) => {
// Send data.ref to your server for verification, then update your UI.
}},
onCancel={(data) => {
// Send data.ref to your server for verification, then update your UI.
}}
}}
sessionToken="sandbox_..."
merchantId="abc123"
/>import ForageCheckoutSDK
let checkout = Checkout(
config: CheckoutConfig(
action: "checkout",
data: CheckoutData(
deliveryAddress: DeliveryAddress(
country: "US",
line1: "4121 Santa Monica Blvd",
city: "Los Angeles",
zipcode: "90029",
state: "CA"
),
productList: [],
isDelivery: true,
supportedBenefits: ["snap", "ebt_cash", "non_ebt"],
ebtPaymentMethod: "f629aa1bf3"
),
onInit: { data in
// Send data.ref to your server for verification.
},
onComplete: { data in
// Send data.ref to your server for verification, then update your UI.
},
onCancel: { data in
// Send data.ref to your server for verification, then update your UI.
}
),
sessionToken: "sandbox_...",
merchantID: "abc123",
)import com.joinforage.checkout.Checkout
import com.joinforage.checkout.CheckoutAddress
import com.joinforage.checkout.CheckoutConfig
import com.joinforage.checkout.CheckoutData
val checkout = Checkout(
config = CheckoutConfig(
action = "checkout",
data = CheckoutData(
deliveryAddress = CheckoutAddress(
country = "US",
line1 = "4121 Santa Monica Blvd",
city = "Los Angeles",
zipcode = "90029",
state = "CA"
),
productList = emptyList(),
isDelivery = true,
supportedBenefits = listOf("snap", "ebt_cash", "non_ebt"),
ebtPaymentMethod = "f629aa1bf3"
),
onInit = { data ->
// Send data.ref to your server for verification.
},
onComplete = { data ->
// Send data.ref to your server for verification, then update your UI.
},
onCancel = { data ->
// Send data.ref to your server for verification, then update your UI.
}
),
sessionToken = "sandbox_...",
merchantId = "abc123",
)The onComplete and onCancel callbacks return the same Order objects described above. Verify the final outcome on your server with GET /orders/{ref} (/get-order) or through a verified webhook event.
Updated about 2 hours ago
