Skip to main content

Build Commerce Experiences Across Multiple Merchants

Satsuma provides developers with a unified API to search products, manage carts, and place orders across hundreds of merchants. One API, consistent data format, real-time inventory.

Search Products

Query inventory across all merchants with filters for location, category, and availability

Manage Carts

Create merchant-specific carts and manage items before checkout

Place Orders

Submit orders with tokenized payments and receive real-time status updates

Quick Start

# Search products
curl 'https://api.satsuma.ai/product?query=wireless+headphones&latitude=37.7749&longitude=-122.4194&distance=10mi' \
  -H 'Authorization: sk_live_your_api_key'

# Create cart
curl -X POST 'https://api.satsuma.ai/cart' \
  -H 'Authorization: sk_live_your_api_key' \
  -H 'Content-Type: application/json' \
  -d '{"location_id": "loc_abc123", "user_id": "user_xyz789", "status": "Active"}'

# Add items to cart
curl -X POST 'https://api.satsuma.ai/cart/{cart_id}/item' \
  -H 'Authorization: sk_live_your_api_key' \
  -H 'Content-Type: application/json' \
  -d '{"product_id": "prod_123", "product_name": "Wireless Headphones", "quantity": 2}'

# Place order
curl -X POST 'https://api.satsuma.ai/order' \
  -H 'Authorization: sk_live_your_api_key' \
  -H 'Content-Type: application/json' \
  -d '{"location_id": "loc_abc123", "fulfillment_method": "Delivery", "customer": {"id": "user_xyz789", "name": "John Doe", "address": {"street_address": "123 Main St", "city": "San Francisco", "region": "CA", "postal_code": "94105", "country": "US"}}, "items": [{"product_id": "prod_123", "quantity": 2}]}'
import requests

headers = {'Authorization': 'sk_live_your_api_key'}

# Search products
products_response = requests.get(
    'https://api.satsuma.ai/product',
    headers=headers,
    params={
        'query': 'wireless headphones',
        'latitude': 37.7749,
        'longitude': -122.4194,
        'distance': '10mi'
    }
)
products = products_response.json()

# Create cart
cart_response = requests.post(
    'https://api.satsuma.ai/cart',
    headers={**headers, 'Content-Type': 'application/json'},
    json={'location_id': 'loc_abc123', 'user_id': 'user_xyz789', 'status': 'Active'}
)
cart = cart_response.json()

# Add items to cart
requests.post(
    f'https://api.satsuma.ai/cart/{cart["data"]}/item',
    headers={**headers, 'Content-Type': 'application/json'},
    json={'product_id': 'prod_123', 'product_name': 'Wireless Headphones', 'quantity': 2}
)

# Place order
order_response = requests.post(
    'https://api.satsuma.ai/order',
    headers={**headers, 'Content-Type': 'application/json'},
    json={
        'location_id': 'loc_abc123',
        'fulfillment_method': 'Delivery',
        'customer': {
            'id': 'user_xyz789',
            'name': 'John Doe',
            'address': {
                'street_address': '123 Main St',
                'city': 'San Francisco',
                'region': 'CA',
                'postal_code': '94105',
                'country': 'US'
            }
        },
        'items': [{'product_id': 'prod_123', 'quantity': 2}]
    }
)
order = order_response.json()
// Search products across all merchants
const products = await fetch('https://api.satsuma.ai/product?query=wireless+headphones&latitude=37.7749&longitude=-122.4194&distance=10mi', {
  headers: { 'Authorization': 'sk_live_your_api_key' }
});

// Create a cart for a specific location
const cartResponse = await fetch('https://api.satsuma.ai/cart', {
  method: 'POST',
  headers: { 
    'Authorization': 'sk_live_your_api_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    location_id: 'loc_abc123',
    user_id: 'user_xyz789',
    status: 'Active'
  })
});
const cart = await cartResponse.json();

// Add items to cart
await fetch(`https://api.satsuma.ai/cart/${cart.data}/item`, {
  method: 'POST',
  headers: { 
    'Authorization': 'sk_live_your_api_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    product_id: 'prod_123',
    product_name: 'Wireless Headphones',
    quantity: 2
  })
});

// Place the order
const order = await fetch('https://api.satsuma.ai/order', {
  method: 'POST',
  headers: { 
    'Authorization': 'sk_live_your_api_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    location_id: 'loc_abc123',
    fulfillment_method: 'Delivery',
    customer: {
      id: 'user_xyz789',
      name: 'John Doe',
      address: {
        street_address: '123 Main St',
        city: 'San Francisco',
        region: 'CA',
        postal_code: '94105',
        country: 'US'
      }
    },
    items: [{ product_id: 'prod_123', quantity: 2 }]
  })
});
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;

HttpClient client = HttpClient.newHttpClient();
ObjectMapper mapper = new ObjectMapper();
String apiKey = "sk_live_your_api_key";

// Search products
String searchUrl = "https://api.satsuma.ai/product?query=wireless+headphones&latitude=37.7749&longitude=-122.4194&distance=10mi";
HttpRequest searchRequest = HttpRequest.newBuilder()
    .uri(URI.create(searchUrl))
    .header("Authorization", apiKey)
    .build();
HttpResponse<String> productsResponse = client.send(searchRequest, HttpResponse.BodyHandlers.ofString());

// Create cart
String cartData = mapper.writeValueAsString(Map.of(
    "location_id", "loc_abc123",
    "user_id", "user_xyz789",
    "status", "Active"
));
HttpRequest cartRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://api.satsuma.ai/cart"))
    .header("Authorization", apiKey)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(cartData))
    .build();
HttpResponse<String> cartResponse = client.send(cartRequest, HttpResponse.BodyHandlers.ofString());
JsonNode cart = mapper.readTree(cartResponse.body());

// Add items and place order
String cartId = cart.get("data").asText();
String itemData = mapper.writeValueAsString(Map.of(
    "product_id", "prod_123",
    "product_name", "Wireless Headphones",
    "quantity", 2
));
HttpRequest itemRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://api.satsuma.ai/cart/" + cartId + "/item"))
    .header("Authorization", apiKey)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(itemData))
    .build();
client.send(itemRequest, HttpResponse.BodyHandlers.ofString());

Map<String, Object> orderMap = new HashMap<>();
orderMap.put("location_id", "loc_abc123");
orderMap.put("fulfillment_method", "Delivery");
orderMap.put("customer", Map.of(
    "id", "user_xyz789",
    "name", "John Doe",
    "address", Map.of(
        "street_address", "123 Main St",
        "city", "San Francisco",
        "region", "CA",
        "postal_code", "94105",
        "country", "US"
    )
));
orderMap.put("items", List.of(Map.of("product_id", "prod_123", "quantity", 2)));
String orderData = mapper.writeValueAsString(orderMap);
HttpRequest orderRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://api.satsuma.ai/order"))
    .header("Authorization", apiKey)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(orderData))
    .build();
HttpResponse<String> orderResponse = client.send(orderRequest, HttpResponse.BodyHandlers.ofString());

Core Concepts

Multi-Merchant Architecture

  • Product Search: Query across all merchants simultaneously
  • Merchant-Specific Carts: Each cart belongs to a single merchant
  • Independent Orders: Orders are placed with individual merchants
  • Unified Response Format: Consistent data structure across all merchants

Key Constraints

  • Carts cannot contain items from multiple merchants
  • Each order is submitted to a single merchant

What You Can Build

AI Shopping Assistants

Help users find products and complete purchases through natural conversation

Local Discovery Apps

Find products available near users with location-based search

Automated Purchasing

Build systems that reorder products automatically based on rules

API Capabilities

curl 'https://api.satsuma.ai/product?query=coffee&merchantId=merch_123&category=Beverages&latitude=37.7749&longitude=-122.4194&distance=5mi' \
  -H 'Authorization: your-api-key'
import requests

params = {
    'query': 'coffee',
    'merchantId': 'merch_123',
    'category': 'Beverages', 
    'latitude': 37.7749,
    'longitude': -122.4194,
    'distance': '5mi'
}

response = requests.get(
    'https://api.satsuma.ai/product',
    headers={'Authentication': 'your-api-key'},
    params=params
)
results = response.json()
// Search with multiple filters
const results = await fetch('https://api.satsuma.ai/product?' + new URLSearchParams({
    query: 'coffee',
    merchantId: 'merch_123',  // Optional: filter by merchant
    category: 'Beverages',
    latitude: 37.7749,
    longitude: -122.4194,
    distance: '5mi'
}), {
  headers: { 'Authorization': 'your-api-key' }
});
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.URI;

HttpClient client = HttpClient.newHttpClient();
String url = "https://api.satsuma.ai/product?query=coffee&merchantId=merch_123&category=Beverages&latitude=37.7749&longitude=-122.4194&distance=5mi";

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create(url))
    .header("Authorization", "your-api-key")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

Cart Management

# Create cart for specific location
curl -X POST 'https://api.satsuma.ai/cart' \
  -H 'Authorization: your-api-key' \
  -H 'Content-Type: application/json' \
  -d '{"location_id": "loc_123", "user_id": "user_456", "status": "Active"}'

# Add items to cart
curl -X POST 'https://api.satsuma.ai/cart/{cart_id}/item' \
  -H 'Authorization: your-api-key' \
  -H 'Content-Type: application/json' \
  -d '{"product_id": "prod_789", "product_name": "Premium Coffee", "quantity": 3}'

# Update item quantity
curl -X PUT 'https://api.satsuma.ai/cart/{cart_id}/item/{item_id}' \
  -H 'Authorization: your-api-key' \
  -H 'Content-Type: application/json' \
  -d '{"quantity": 5}'
import requests

headers = {'Authorization': 'your-api-key', 'Content-Type': 'application/json'}

# Create cart for specific location
cart_data = {'location_id': 'loc_123', 'user_id': 'user_456', 'status': 'Active'}
cart_response = requests.post('https://api.satsuma.ai/cart', headers=headers, json=cart_data)
cart = cart_response.json()

# Add items from the same location
item_data = {'product_id': 'prod_789', 'product_name': 'Premium Coffee', 'quantity': 3}
requests.post(f'https://api.satsuma.ai/cart/{cart["data"]}/item', headers=headers, json=item_data)

# Update quantities
update_data = {'quantity': 5}
requests.put(f'https://api.satsuma.ai/cart/{cart["data"]}/item/{item_id}', headers=headers, json=update_data)
// Carts are location-specific
const cartResponse = await fetch('https://api.satsuma.ai/cart', {
  method: 'POST',
  headers: { 
    'Authorization': 'your-api-key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    location_id: 'loc_123',  // Required: carts belong to one location
    user_id: 'user_456',
    status: 'Active'
  })
});
const cart = await cartResponse.json();

// Add items from the same location
await fetch(`https://api.satsuma.ai/cart/${cart.data}/item`, {
  method: 'POST',
  headers: { 
    'Authorization': 'your-api-key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    product_id: 'prod_789',  // Must be from loc_123
    product_name: 'Premium Coffee',
    quantity: 3
  })
});

// Update quantities
await fetch(`https://api.satsuma.ai/cart/${cart.data}/item/${item_id}`, {
  method: 'PUT',
  headers: { 
    'Authorization': 'your-api-key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    quantity: 5
  })
});
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.URI;
import com.fasterxml.jackson.databind.ObjectMapper;

HttpClient client = HttpClient.newHttpClient();
ObjectMapper mapper = new ObjectMapper();
String apiKey = "your-api-key";

// Create cart for specific location
String cartData = mapper.writeValueAsString(Map.of("location_id", "loc_123", "user_id", "user_456", "status", "Active"));
HttpRequest cartRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://api.satsuma.ai/cart"))
    .header("Authorization", apiKey)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(cartData))
    .build();
HttpResponse<String> cartResponse = client.send(cartRequest, HttpResponse.BodyHandlers.ofString());

// Add items and update quantities
String itemData = mapper.writeValueAsString(Map.of("product_id", "prod_789", "product_name", "Premium Coffee", "quantity", 3));
HttpRequest itemRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://api.satsuma.ai/cart/" + cartId + "/item"))
    .header("Authorization", apiKey)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(itemData))
    .build();
client.send(itemRequest, HttpResponse.BodyHandlers.ofString());

Order Processing

# Create order directly
curl -X POST 'https://api.satsuma.ai/order' \
  -H 'Authorization: your-api-key' \
  -H 'Content-Type: application/json' \
  -d '{"location_id": "loc_123", "fulfillment_method": "Delivery", "dropoff_instructions": "Leave at door", "customer": {"id": "user_456", "name": "Jane Doe", "address": {"street_address": "456 Oak St", "city": "San Francisco", "region": "CA", "postal_code": "94105", "country": "US"}}, "items": [{"product_id": "prod_789", "quantity": 3}]}'

# Get payment intent for order
curl 'https://api.satsuma.ai/order/{order_id}/payment-intent' \
  -H 'Authorization: your-api-key'
import requests

headers = {'Authorization': 'your-api-key', 'Content-Type': 'application/json'}

# Create order directly
order_data = {
    'location_id': 'loc_123',
    'fulfillment_method': 'Delivery',
    'dropoff_instructions': 'Leave at door',
    'customer': {
        'id': 'user_456',
        'name': 'Jane Doe',
        'address': {
            'street_address': '456 Oak St',
            'city': 'San Francisco',
            'region': 'CA',
            'postal_code': '94105',
            'country': 'US'
        }
    },
    'items': [{'product_id': 'prod_789', 'quantity': 3}]
}
order_response = requests.post('https://api.satsuma.ai/order', headers=headers, json=order_data)
order = order_response.json()

# Get payment intent
payment_response = requests.get(f'https://api.satsuma.ai/order/{order["data"]["id"]}/payment-intent', headers=headers)
payment_intent = payment_response.json()['data']
print(payment_intent)  # Contains payment_intent_id and client_secret
// Create order directly
const orderResponse = await fetch('https://api.satsuma.ai/order', {
  method: 'POST',
  headers: { 
    'Authorization': 'your-api-key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    location_id: 'loc_123',
    fulfillment_method: 'Delivery',
    dropoff_instructions: 'Leave at door',
    customer: {
      id: 'user_456',
      name: 'Jane Doe',
      address: {
        street_address: '456 Oak St',
        city: 'San Francisco',
        region: 'CA',
        postal_code: '94105',
        country: 'US'
      }
    },
    items: [{ product_id: 'prod_789', quantity: 3 }]
  })
});
const order = await orderResponse.json();

// Get payment intent
const paymentResponse = await fetch(`https://api.satsuma.ai/order/${order.data.id}/payment-intent`, {
  headers: { 'Authorization': 'your-api-key' }
});
const paymentIntent = await paymentResponse.json();
console.log(paymentIntent.data); // Contains payment_intent_id and client_secret
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.URI;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;

HttpClient client = HttpClient.newHttpClient();
ObjectMapper mapper = new ObjectMapper();
String apiKey = "your-api-key";

// Create order directly
Map<String, Object> orderMap = new HashMap<>();
orderMap.put("location_id", "loc_123");
orderMap.put("fulfillment_method", "Delivery");
orderMap.put("dropoff_instructions", "Leave at door");
orderMap.put("customer", Map.of(
    "id", "user_456",
    "name", "Jane Doe",
    "address", Map.of(
        "street_address", "456 Oak St",
        "city", "San Francisco",
        "region", "CA",
        "postal_code", "94105",
        "country", "US"
    )
));
orderMap.put("items", List.of(Map.of("product_id", "prod_789", "quantity", 3)));
String orderData = mapper.writeValueAsString(orderMap);
HttpRequest orderRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://api.satsuma.ai/order"))
    .header("Authorization", apiKey)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(orderData))
    .build();
HttpResponse<String> orderResponse = client.send(orderRequest, HttpResponse.BodyHandlers.ofString());

// Get payment intent
JsonNode order = mapper.readTree(orderResponse.body());
String orderId = order.get("data").get("id").asText();
HttpRequest paymentRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://api.satsuma.ai/order/" + orderId + "/payment-intent"))
    .header("Authorization", apiKey)
    .build();
HttpResponse<String> paymentResponse = client.send(paymentRequest, HttpResponse.BodyHandlers.ofString());
JsonNode paymentIntent = mapper.readTree(paymentResponse.body());
System.out.println(paymentIntent.get("data"));

Authentication

All API requests require authentication via API key:
curl https://api.satsuma.ai/product?latitude=37.7749&longitude=-122.4194 \
  -H "Authorization: sk_live_your_api_key"
import requests

headers = {'Authorization': 'sk_live_your_api_key'}
response = requests.get('https://api.satsuma.ai/product?latitude=37.7749&longitude=-122.4194', headers=headers)
const response = await fetch('https://api.satsuma.ai/product?latitude=37.7749&longitude=-122.4194', {
  headers: { 'Authorization': 'sk_live_your_api_key' }
});
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.URI;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.satsuma.ai/product?latitude=37.7749&longitude=-122.4194"))
    .header("Authorization", "sk_live_your_api_key")
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
Get your API key from the developer dashboard.

Rate Limits

Development

Free Tier
  • 1,000 requests/month
  • 5 requests/second
  • Sandbox environment

Production

Paid Plans
  • 50K-500K requests/month
  • 25-100 requests/second
  • Production access

Next Steps

API Reference

Explore all endpoints and parameters

SDKs

JavaScript, Python, and Go libraries

Need Help?