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
Product Search
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());
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?
- Documentation: You’re here!
- API Status: status.satsuma.ai
- Support: support@satsuma.ai