---
updatedAt: 2026-03-17T16:36:59.000Z
agentTools:
  projectIndex: https://docs.joinforage.app/llms.txt
---

# Quickstart

### Start a session

The client (your server) will initiate a session with Forage Checkout via the RESTful API. Your server will POST the order totals and specify where to redirect your customer after they complete Forage Checkout, either by successfully submitting payments or canceling the order.

A successful response from Forage's server will return:

* An `Order` object in the body. You should save the order's reference number for your records.
* A `redirect_url`. You should redirect your customer to the `redirect_url` to complete payment.

Below is an example request and response with added context:

#### Client Request

```curl
curl --request POST \
     --url https://api.sandbox.joinforage.app/api/sessions/ \
     --header 'Authorization: Bearer <authentication-token>' \
     --header 'Idempotency-Key: <idempotency-key>' \
     --header 'Merchant-Account: <merchant-id>' \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '
{
  "delivery_address": {
    "city": "San Francisco",
    "country": "US",
    "line1": "1856 Market St.",
    "line2": "Unit 3",
    "zipcode": "94102",
    "state": "CA"
  },
  "is_delivery": true,
  "success_redirect_url": "<https://your-app.com/receipt>",
  "cancel_redirect_url": "<https://your-app.com/order-canceled>"
}
'
```
```python
import requests

response = requests.post(
    "https://api.sandbox.joinforage.app/api/sessions/",
    headers={
        "Authorization": "Bearer <authentication-token>",
        "Idempotency-Key": "<idempotency-key>",
        "Merchant-Account": "<merchant-id>",
        "Accept": "application/json",
        "Content-Type": "application/json",
    },
    json={
        "delivery_address": {
            "city": "San Francisco",
            "country": "US",
            "line1": "1856 Market St.",
            "line2": "Unit 3",
            "zipcode": "94102",
            "state": "CA",
        },
        "is_delivery": True,
        "success_redirect_url": "https://your-app.com/receipt",
        "cancel_redirect_url": "https://your-app.com/order-canceled",
    },
)
print(response.json())
```
```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

HttpClient client = HttpClient.newHttpClient();

String json = """
    {
      "delivery_address": {
        "city": "San Francisco",
        "country": "US",
        "line1": "1856 Market St.",
        "line2": "Unit 3",
        "zipcode": "94102",
        "state": "CA"
      },
      "is_delivery": true,
      "success_redirect_url": "https://your-app.com/receipt",
      "cancel_redirect_url": "https://your-app.com/order-canceled"
    }
    """;

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.sandbox.joinforage.app/api/sessions/"))
    .header("Authorization", "Bearer <authentication-token>")
    .header("Idempotency-Key", "<idempotency-key>")
    .header("Merchant-Account", "<merchant-id>")
    .header("Accept", "application/json")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(json))
    .build();

HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
```
```javascript Node
const response = await fetch(
  "https://api.sandbox.joinforage.app/api/sessions/",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer <authentication-token>",
      "Idempotency-Key": "<idempotency-key>",
      "Merchant-Account": "<merchant-id>",
      Accept: "application/json",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      delivery_address: {
        city: "San Francisco",
        country: "US",
        line1: "1856 Market St.",
        line2: "Unit 3",
        zipcode: "94102",
        state: "CA",
      },
      is_delivery: true,
      success_redirect_url: "https://your-app.com/receipt",
      cancel_redirect_url: "https://your-app.com/order-canceled",
    }),
  }
);
const data = await response.json();
console.log(data);
```
```ruby
require 'net/http'
require 'json'

uri = URI("https://api.sandbox.joinforage.app/api/sessions/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri.path)
request["Authorization"] = "Bearer <authentication-token>"
request["Idempotency-Key"] = "<idempotency-key>"
request["Merchant-Account"] = "<merchant-id>"
request["Accept"] = "application/json"
request["Content-Type"] = "application/json"
request.body = {
  delivery_address: {
    city: "San Francisco",
    country: "US",
    line1: "1856 Market St.",
    line2: "Unit 3",
    zipcode: "94102",
    state: "CA"
  },
  is_delivery: true,
  success_redirect_url: "https://your-app.com/receipt",
  cancel_redirect_url: "https://your-app.com/order-canceled"
}.to_json

response = http.request(request)
puts JSON.parse(response.body)
```

* `delivery_address`: The address where the order will either be delivered or picked up. Required by FNS.
* `is_delivery`: Whether the order will be delivered or picked up. Required by FNS.
* `success_redirect_url` : The page to redirect your customer to after successfully paying for their order.
* `cancel_redirect_url` : The page to redirect your customer to if they cancel their order before successful payment. Must be supplied on the initial session request

Required Headers:

* `token`: This alphanumeric string is unique to your client. Keep it a secret as it authorizes Forage to execute transactions.
* `merchant-identifier`: This numeric string represents the authorized FNS merchant for whom you want to make the transaction.
* `idempotency-key`: This alphanumeric string allows you to make the same sessions request twice, without creating multiple sessions on Forage's backend, as long as you pass the same value in this header for both requests. This feature is useful if any networking errors prevent the `201 CREATED` response from reaching your servers after the session was created.

#### Response

```json
{
  "ref": "9ebe44e3eb",
  "snap_total": 120.25,
  "ebt_cash_total": 79.75,
  "remaining_total": 10.00,
  "success_redirect_url": "https://your-app.com/receipt",
  "cancel_redirect_url": "https://your-app.com/order-canceled",
  "status": "draft",
  "redirect_url": "https://joinforage.app/sessions?order=9ebe44e3eb"
}
```

* `ref`: Store a reference to this Order object for your records.
* `redirect_url`: Redirect your customer to this page so they can complete payment.

### Request transaction outcome from Forage

After a customer completes the Fully Hosted Checkout flow, request the transaction outcome from Forage. Pass the stored Order `ref`, in a GET to [`/orders/{ref}`](https://docs.joinforage.app/reference/get-order), as in the following example:

```curl
curl --request GET \
     --url https://api.sandbox.joinforage.app/api/orders/ref/ \
     --header 'accept: application/json'
```
```python
import requests

response = requests.get(
    "https://api.sandbox.joinforage.app/api/orders/<order_ref>/",
    headers={
        "Authorization": "Bearer <authentication-token>",
        "Merchant-Account": "<merchant-id>",
        "Accept": "application/json",
    },
)
print(response.json())
```
```java
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/orders/<order_ref>/"))
    .header("Authorization", "Bearer <authentication-token>")
    .header("Merchant-Account", "<merchant-id>")
    .header("Accept", "application/json")
    .GET()
    .build();

HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
```
```javascript Node
const response = await fetch(
  "https://api.sandbox.joinforage.app/api/orders/<order_ref>/",
  {
    headers: {
      Authorization: "Bearer <authentication-token>",
      "Merchant-Account": "<merchant-id>",
      Accept: "application/json",
    },
  }
);
const data = await response.json();
console.log(data);
```
```ruby
require 'net/http'
require 'json'

uri = URI("https://api.sandbox.joinforage.app/api/orders/<order_ref>/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri.path)
request["Authorization"] = "Bearer <authentication-token>"
request["Merchant-Account"] = "<merchant-id>"
request["Accept"] = "application/json"

response = http.request(request)
puts JSON.parse(response.body)
```

Forage responds with a JSON object including details about the order, and redirects the customer to either the `success_redirect_url` or the `cancel_redirect_url`. You set these redirect values when you [started the session](#start-a-session).

```json
{
  "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,
  "success_redirect_url": "https://your-app.com/receipt",
  "cancel_redirect_url": "https://your-app.com/order-canceled",
  "supported_benefits": [
    "snap",
    "ebt_cash",
    "non_ebt"
  ],
  "customer_id": "cus_AJ6yA7mRH34mJT",
  "ref": "93410bcaff",
  "status": "draft",
  "payments": [],
  "refunds": [],
  "receipt": {
    "ref_number": "93410bcaff",
    "snap_amount": "25.99",
    "ebt_cash_amount": "10.99",
    "other_amount": "5.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": "Refund",
    "created": "2021-06-16T00:11:50.000000Z-07:00"
  }
}
```

### How to start a session with a saved payment method

If you recognize a customer, then you can start a session and pre-populate it with a payment method that the customer saved during a past session.

#### Client Request

```curl
curl -X 'POST' \
     'https://api.sandbox.joinforage.app/api/sessions/' \
     -H 'Accept: application/json' \
     -H 'Content-Type: application/json' \
     -H 'Authorization: Bearer ${token}' \
     -H 'Merchant-Account: ${merchant identifier}' \
     -H 'Idempotency-Key: <idempotency-key>' \
     -d '{
  "delivery_address": {
    "country": "US",
    "line1": "4121 Santa Monica Blvd",
    "city": "Los Angeles",
    "zipcode": "90029",
    "state": "CA"
  },
  "product_list": [],
  "is_delivery": true,
  "success_redirect_url": "https://www.joinforage.com/?status=SUCCEEDED",
  "cancel_redirect_url": "https://www.joinforage.com/?status=CANCELED",
  "supported_benefits": [
    "snap",
    "ebt_cash",
    "non_ebt"
  ],
  "ebt_payment_method": "f629aa1bf3"
}'
```
```python
import requests

response = requests.post(
    "https://api.sandbox.joinforage.app/api/sessions/",
    headers={
        "Authorization": "Bearer <authentication-token>",
        "Idempotency-Key": "<idempotency-key>",
        "Merchant-Account": "<merchant-id>",
        "Accept": "application/json",
        "Content-Type": "application/json",
    },
    json={
        "delivery_address": {
            "country": "US",
            "line1": "4121 Santa Monica Blvd",
            "city": "Los Angeles",
            "zipcode": "90029",
            "state": "CA",
        },
        "product_list": [],
        "is_delivery": True,
        "success_redirect_url": "https://www.joinforage.com/?status=SUCCEEDED",
        "cancel_redirect_url": "https://www.joinforage.com/?status=CANCELED",
        "supported_benefits": ["snap", "ebt_cash", "non_ebt"],
        "ebt_payment_method": "f629aa1bf3",
    },
)
print(response.json())
```
```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

HttpClient client = HttpClient.newHttpClient();

String json = """
    {
      "delivery_address": {
        "country": "US",
        "line1": "4121 Santa Monica Blvd",
        "city": "Los Angeles",
        "zipcode": "90029",
        "state": "CA"
      },
      "product_list": [],
      "is_delivery": true,
      "success_redirect_url": "https://www.joinforage.com/?status=SUCCEEDED",
      "cancel_redirect_url": "https://www.joinforage.com/?status=CANCELED",
      "supported_benefits": ["snap", "ebt_cash", "non_ebt"],
      "ebt_payment_method": "f629aa1bf3"
    }
    """;

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.sandbox.joinforage.app/api/sessions/"))
    .header("Authorization", "Bearer <authentication-token>")
    .header("Idempotency-Key", "<idempotency-key>")
    .header("Merchant-Account", "<merchant-id>")
    .header("Accept", "application/json")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(json))
    .build();

HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
```
```javascript Node
const response = await fetch(
  "https://api.sandbox.joinforage.app/api/sessions/",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer <authentication-token>",
      "Idempotency-Key": "<idempotency-key>",
      "Merchant-Account": "<merchant-id>",
      Accept: "application/json",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      delivery_address: {
        country: "US",
        line1: "4121 Santa Monica Blvd",
        city: "Los Angeles",
        zipcode: "90029",
        state: "CA",
      },
      product_list: [],
      is_delivery: true,
      success_redirect_url: "https://www.joinforage.com/?status=SUCCEEDED",
      cancel_redirect_url: "https://www.joinforage.com/?status=CANCELED",
      supported_benefits: ["snap", "ebt_cash", "non_ebt"],
      ebt_payment_method: "f629aa1bf3",
    }),
  }
);
const data = await response.json();
console.log(data);
```
```ruby
require 'net/http'
require 'json'

uri = URI("https://api.sandbox.joinforage.app/api/sessions/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri.path)
request["Authorization"] = "Bearer <authentication-token>"
request["Idempotency-Key"] = "<idempotency-key>"
request["Merchant-Account"] = "<merchant-id>"
request["Accept"] = "application/json"
request["Content-Type"] = "application/json"
request.body = {
  delivery_address: {
    country: "US",
    line1: "4121 Santa Monica Blvd",
    city: "Los Angeles",
    zipcode: "90029",
    state: "CA"
  },
  product_list: [],
  is_delivery: true,
  success_redirect_url: "https://www.joinforage.com/?status=SUCCEEDED",
  cancel_redirect_url: "https://www.joinforage.com/?status=CANCELED",
  supported_benefits: %w[snap ebt_cash non_ebt],
  ebt_payment_method: "f629aa1bf3"
}.to_json

response = http.request(request)
puts JSON.parse(response.body)
```

#### Response

```json
{
  "delivery_address": {
    "country": "US",
    "line1": "4121 Santa Monica Blvd",
    "city": "Los Angeles",
    "zipcode": "90029",
    "state": "CA"
  },
  "snap_total": 10,
  "ebt_cash_total": 20,
  "remaining_total": 0,
  "product_list": [],
  "is_delivery": true,
  "success_redirect_url": "https://www.joinforage.com/?status=SUCCEEDED",
  "cancel_redirect_url": "https://www.joinforage.com/?status=CANCELED",
  "supported_benefits": [
    "snap",
    "ebt_cash",
    "non_ebt"
  ],
  "ebt_payment_method": "f629aa1bf3"
}
```

# Sibling pages

* [Introduction](https://docs.joinforage.app/docs/fully-hosted.md)
* [Reuse Payment Methods](https://docs.joinforage.app/docs/fully-hosted-reuse-payment-methods.md)
* [Errors](https://docs.joinforage.app/docs/fully-hosted-errors.md)