Create a sandbox campaign
Creates a marketing campaign in your sandbox. A campaign is a budget with a discount attached: it discounts an order like a promotion, but stops once its budget is spent, so this is how budget exhaustion is exercised without spending a real one.
Use applies_to to scope where the campaign applies — online for storefront orders, pos
for in-store, or all for both. A campaign scoped to one channel does not discount the other.
Every field is optional; the defaults create an active campaign with a 1000.00 budget and a 10%
discount, starting today and running for 30 days. The environment is always set to sandbox by
Galactic Core and is never read from the request body.
Requires a secret test key (tybrite_sk_test_*).
curl --request POST \
--url https://api.tybritelabs.com/v1/sandbox/seed/campaign \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Autumn push",
"budget": 500,
"discount_type": "percentage",
"discount_value": 20,
"applies_to": "online"
}
'import requests
url = "https://api.tybritelabs.com/v1/sandbox/seed/campaign"
payload = {
"name": "Autumn push",
"budget": 500,
"discount_type": "percentage",
"discount_value": 20,
"applies_to": "online"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Autumn push',
budget: 500,
discount_type: 'percentage',
discount_value: 20,
applies_to: 'online'
})
};
fetch('https://api.tybritelabs.com/v1/sandbox/seed/campaign', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.tybritelabs.com/v1/sandbox/seed/campaign",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Autumn push',
'budget' => 500,
'discount_type' => 'percentage',
'discount_value' => 20,
'applies_to' => 'online'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.tybritelabs.com/v1/sandbox/seed/campaign"
payload := strings.NewReader("{\n \"name\": \"Autumn push\",\n \"budget\": 500,\n \"discount_type\": \"percentage\",\n \"discount_value\": 20,\n \"applies_to\": \"online\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.tybritelabs.com/v1/sandbox/seed/campaign")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Autumn push\",\n \"budget\": 500,\n \"discount_type\": \"percentage\",\n \"discount_value\": 20,\n \"applies_to\": \"online\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tybritelabs.com/v1/sandbox/seed/campaign")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Autumn push\",\n \"budget\": 500,\n \"discount_type\": \"percentage\",\n \"discount_value\": 20,\n \"applies_to\": \"online\"\n}"
response = http.request(request)
puts response.read_body{
"campaign": {
"id": "d5814e95-e68b-4a98-95bf-cb945f413052",
"name": "Autumn push",
"type": "seasonal",
"budget": 500,
"budget_spent": 0,
"budget_remaining": 500,
"discount_type": "percentage",
"discount_value": 20,
"applies_to": "online",
"start_date": "2026-09-07",
"end_date": "2026-10-07",
"status": "active",
"environment": "sandbox"
}
}{
"error": {
"code": "invalid_request",
"message": "Invalid request parameters",
"details": "The 'email' field is required"
}
}{
"error": {
"code": "unauthorized",
"message": "Missing or invalid Authorization header"
}
}{
"error": {
"code": "forbidden",
"message": "This operation requires a secret key. Publishable keys cover catalogue reads and the actions a shopper takes for themselves."
}
}{
"error": {
"code": "rate_limited",
"message": "Too many requests for this API key. Please slow down and try again shortly.",
"remaining": 0,
"reset": 1706198400
}
}{
"error": {
"code": "server_error",
"message": "An unexpected error occurred"
}
}Authorizations
API Key Authentication
Use your API key in the Authorization header:
Authorization: Bearer tybrite_sk_live_YOUR_KEY
Key Types:
Secret Keys (Server-Side Only):
- Format:
tybrite_sk_live_*(production) ortybrite_sk_test_*(sandbox) - Full read/write access to all endpoints
- ⚠️ NEVER expose in client-side code or public repositories
- Required for: every write a shopper does not make for themselves, authentication, payment verification, AI recommendations
Publishable Keys (Client-Safe):
- Format:
tybrite_pk_live_*(production) ortybrite_pk_test_*(sandbox) - Catalogue reads, plus the actions a shopper takes for themselves
- ✅ Safe for client-side JavaScript, mobile apps, and public code
- Allowed for: browsing products, search, CMS content, pricing queries, cart and wishlist, reviews, storefront events, and the Agent API's quotes, cart drafts and checkout intents
Endpoint-Specific Requirements:
- Authentication endpoints (
/v1/auth/*): Secret key required - Payment verification (
POST /v1/payments/verify): Secret key required - AI Recommendations (
POST /v1/recommendations): Secret key required - Semantic Search (
POST /v1/search): Both key types allowed (read-only operation) - Shopper actions (cart, wishlist, reviews, storefront events, Agent API quotes, cart drafts and checkout intents): Both key types allowed
- All other write operations: Secret key required
- All read operations: Both key types allowed
Using a publishable key for restricted operations returns 403 Forbidden.
Body
Defaults to a generated Sandbox campaign … name.
Total spend the campaign may draw down. Must be greater than zero.
percentage, fixed_amount Must be greater than zero.
Which sales channel the campaign discounts.
all, online, pos Defaults to today. Cannot be in the past.
Defaults to 30 days from today.
Response
Sandbox campaign created.
A campaign created in the sandbox — a budget with a discount attached. It discounts an order
like a promotion but stops once budget_spent reaches budget.
Show child attributes
Show child attributes
curl --request POST \
--url https://api.tybritelabs.com/v1/sandbox/seed/campaign \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Autumn push",
"budget": 500,
"discount_type": "percentage",
"discount_value": 20,
"applies_to": "online"
}
'import requests
url = "https://api.tybritelabs.com/v1/sandbox/seed/campaign"
payload = {
"name": "Autumn push",
"budget": 500,
"discount_type": "percentage",
"discount_value": 20,
"applies_to": "online"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Autumn push',
budget: 500,
discount_type: 'percentage',
discount_value: 20,
applies_to: 'online'
})
};
fetch('https://api.tybritelabs.com/v1/sandbox/seed/campaign', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.tybritelabs.com/v1/sandbox/seed/campaign",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Autumn push',
'budget' => 500,
'discount_type' => 'percentage',
'discount_value' => 20,
'applies_to' => 'online'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.tybritelabs.com/v1/sandbox/seed/campaign"
payload := strings.NewReader("{\n \"name\": \"Autumn push\",\n \"budget\": 500,\n \"discount_type\": \"percentage\",\n \"discount_value\": 20,\n \"applies_to\": \"online\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.tybritelabs.com/v1/sandbox/seed/campaign")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Autumn push\",\n \"budget\": 500,\n \"discount_type\": \"percentage\",\n \"discount_value\": 20,\n \"applies_to\": \"online\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tybritelabs.com/v1/sandbox/seed/campaign")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Autumn push\",\n \"budget\": 500,\n \"discount_type\": \"percentage\",\n \"discount_value\": 20,\n \"applies_to\": \"online\"\n}"
response = http.request(request)
puts response.read_body{
"campaign": {
"id": "d5814e95-e68b-4a98-95bf-cb945f413052",
"name": "Autumn push",
"type": "seasonal",
"budget": 500,
"budget_spent": 0,
"budget_remaining": 500,
"discount_type": "percentage",
"discount_value": 20,
"applies_to": "online",
"start_date": "2026-09-07",
"end_date": "2026-10-07",
"status": "active",
"environment": "sandbox"
}
}{
"error": {
"code": "invalid_request",
"message": "Invalid request parameters",
"details": "The 'email' field is required"
}
}{
"error": {
"code": "unauthorized",
"message": "Missing or invalid Authorization header"
}
}{
"error": {
"code": "forbidden",
"message": "This operation requires a secret key. Publishable keys cover catalogue reads and the actions a shopper takes for themselves."
}
}{
"error": {
"code": "rate_limited",
"message": "Too many requests for this API key. Please slow down and try again shortly.",
"remaining": 0,
"reset": 1706198400
}
}{
"error": {
"code": "server_error",
"message": "An unexpected error occurred"
}
}
