Create a studio-scoped guest checkout link
Requires checkout_links:write and print_orders:write plus access to the explicit studio. Anonymous sessions cannot use this management lane. The credential persists the sandbox or production checkout lane: a br_test_ key creates an explicitly sandboxed, non-payable link with preview_status=non_payable and no URL; an explicitly production link is payable, subject to normal guest-checkout policy and payment readiness. A historical missing-lane staff or guardian link remains compatibility-payable only when it has no machine API-key provenance. A missing-lane machine link fails closed. Live creation returns share_url only for the first successful create response. Reusing an idempotency key with a different request fingerprint returns checkout_link_conflict.
curl --request POST \
--url https://api.batchrelay.com/v1/studios/{studio_id}/checkout-links \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"event_id": "<string>",
"recipient": {
"athlete_event_entry_id": "<string>",
"guardian_id": "<string>"
},
"sellable": {
"id": "<string>",
"quantity": 50,
"digital_configuration_id": "<string>",
"prepared_asset_assignment_ids": [
"<string>"
],
"variant_id": "<string>"
},
"customizable": false,
"expires_at": "2023-11-07T05:31:56Z",
"promotion": {
"code": "<string>",
"automatic": true,
"offer_id": "<string>"
}
}
'import requests
url = "https://api.batchrelay.com/v1/studios/{studio_id}/checkout-links"
payload = {
"event_id": "<string>",
"recipient": {
"athlete_event_entry_id": "<string>",
"guardian_id": "<string>"
},
"sellable": {
"id": "<string>",
"quantity": 50,
"digital_configuration_id": "<string>",
"prepared_asset_assignment_ids": ["<string>"],
"variant_id": "<string>"
},
"customizable": False,
"expires_at": "2023-11-07T05:31:56Z",
"promotion": {
"code": "<string>",
"automatic": True,
"offer_id": "<string>"
}
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
event_id: '<string>',
recipient: {athlete_event_entry_id: '<string>', guardian_id: '<string>'},
sellable: {
id: '<string>',
quantity: 50,
digital_configuration_id: '<string>',
prepared_asset_assignment_ids: ['<string>'],
variant_id: '<string>'
},
customizable: false,
expires_at: '2023-11-07T05:31:56Z',
promotion: {code: '<string>', automatic: true, offer_id: '<string>'}
})
};
fetch('https://api.batchrelay.com/v1/studios/{studio_id}/checkout-links', 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.batchrelay.com/v1/studios/{studio_id}/checkout-links",
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([
'event_id' => '<string>',
'recipient' => [
'athlete_event_entry_id' => '<string>',
'guardian_id' => '<string>'
],
'sellable' => [
'id' => '<string>',
'quantity' => 50,
'digital_configuration_id' => '<string>',
'prepared_asset_assignment_ids' => [
'<string>'
],
'variant_id' => '<string>'
],
'customizable' => false,
'expires_at' => '2023-11-07T05:31:56Z',
'promotion' => [
'code' => '<string>',
'automatic' => true,
'offer_id' => '<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$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.batchrelay.com/v1/studios/{studio_id}/checkout-links"
payload := strings.NewReader("{\n \"event_id\": \"<string>\",\n \"recipient\": {\n \"athlete_event_entry_id\": \"<string>\",\n \"guardian_id\": \"<string>\"\n },\n \"sellable\": {\n \"id\": \"<string>\",\n \"quantity\": 50,\n \"digital_configuration_id\": \"<string>\",\n \"prepared_asset_assignment_ids\": [\n \"<string>\"\n ],\n \"variant_id\": \"<string>\"\n },\n \"customizable\": false,\n \"expires_at\": \"2023-11-07T05:31:56Z\",\n \"promotion\": {\n \"code\": \"<string>\",\n \"automatic\": true,\n \"offer_id\": \"<string>\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
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.batchrelay.com/v1/studios/{studio_id}/checkout-links")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"event_id\": \"<string>\",\n \"recipient\": {\n \"athlete_event_entry_id\": \"<string>\",\n \"guardian_id\": \"<string>\"\n },\n \"sellable\": {\n \"id\": \"<string>\",\n \"quantity\": 50,\n \"digital_configuration_id\": \"<string>\",\n \"prepared_asset_assignment_ids\": [\n \"<string>\"\n ],\n \"variant_id\": \"<string>\"\n },\n \"customizable\": false,\n \"expires_at\": \"2023-11-07T05:31:56Z\",\n \"promotion\": {\n \"code\": \"<string>\",\n \"automatic\": true,\n \"offer_id\": \"<string>\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.batchrelay.com/v1/studios/{studio_id}/checkout-links")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"event_id\": \"<string>\",\n \"recipient\": {\n \"athlete_event_entry_id\": \"<string>\",\n \"guardian_id\": \"<string>\"\n },\n \"sellable\": {\n \"id\": \"<string>\",\n \"quantity\": 50,\n \"digital_configuration_id\": \"<string>\",\n \"prepared_asset_assignment_ids\": [\n \"<string>\"\n ],\n \"variant_id\": \"<string>\"\n },\n \"customizable\": false,\n \"expires_at\": \"2023-11-07T05:31:56Z\",\n \"promotion\": {\n \"code\": \"<string>\",\n \"automatic\": true,\n \"offer_id\": \"<string>\"\n }\n}"
response = http.request(request)
puts response.read_body{
"expires_at": "2023-11-07T05:31:56Z",
"id": "<string>",
"revocable": true,
"status": "active",
"checkout_intent_id": "<string>",
"currency": "USD",
"discount_cents": 1,
"gross_subtotal_cents": 1,
"guest_checkout_link_id": "<string>",
"net_subtotal_cents": 1,
"offer": {
"id": "<string>",
"revision_id": "<string>",
"code": "<string>",
"label": "<string>",
"revision": 2
},
"payment_state": "not_prepared",
"payment_url": "<string>",
"preview_status": "non_payable",
"promotion": {
"application": "checkout_session",
"currency": "USD",
"discount_type": "percent",
"discount_value": 123,
"offer_id": "<string>",
"revision_id": "<string>",
"code": "<string>",
"discount_cents": 1,
"gross_merchandise_cents": 1,
"net_merchandise_cents": 1
},
"share_url": "<string>",
"stripe_checkout_session_id": "<string>",
"subtotal_cents": 1
}{
"code": "<string>",
"docs_url": "<string>",
"error": "<string>",
"message": "<string>",
"request_id": "<string>"
}{
"code": "<string>",
"docs_url": "<string>",
"error": "<string>",
"message": "<string>",
"request_id": "<string>"
}{
"code": "<string>",
"docs_url": "<string>",
"error": "<string>",
"message": "<string>",
"request_id": "<string>"
}{
"code": "<string>",
"docs_url": "<string>",
"error": "<string>",
"message": "<string>",
"request_id": "<string>"
}{
"code": "<string>",
"docs_url": "<string>",
"error": "<string>",
"message": "<string>",
"request_id": "<string>"
}{
"code": "<string>",
"docs_url": "<string>",
"error": "<string>",
"message": "<string>",
"request_id": "<string>"
}Authorizations
Batch Relay scoped API key or an anonymous Test Mode session. Scope names document required capabilities. Anonymous sessions are sandbox-only and do not authorize studio, event, billing, or Live Mode operations.
Headers
1 - 200Untrusted optional analytics hint naming the calling client surface. It never affects authorization, routing, pricing, or behavior.
1 - 100Untrusted optional analytics hint naming the calling client version. It never affects authorization, routing, pricing, or behavior.
1 - 100Untrusted optional analytics hint naming the invocation mode. It never affects authorization, routing, pricing, or behavior.
1 - 100Path Parameters
Stable public studio ID beginning with stu_. The API never selects a studio implicitly; a local CLI profile name is not a studio ID.
5 - 256^stu_[A-Za-z0-9_-]+$Body
The server resolves current published retail pricing and freezes the non-customizable quote. Client price, tax, payment, provider, recipient-contact, and token fields are not accepted.
1 - 240Show child attributes
Show child attributes
Show child attributes
Show child attributes
Must be in the future and no later than seven days after creation.
Optional server-owned selector. When omitted, the active automatic storewide offer is selected. An invalid explicit selector returns an error and never falls back to a full-price URL.
- Option 1
- Option 2
- Option 3
Show child attributes
Show child attributes
Response
Created or idempotently replayed checkout link. An explicitly sandboxed creation includes preview_status=non_payable and no URL; an explicitly production creation is payable and returns share_url only once for a new Live Mode link.
Safe lifecycle projection. It excludes the token and recipient context. Machine prepare and recover may include opaque server-owned checkout session, intent, guest-link, and promotion identifiers; payment_url is returned only by a successful Live Mode prepare or recover response.
active, checkout_created, fulfilled, revoked, expired Opaque server-owned checkout intent identifier.
"USD"x >= 0x >= 0Opaque server-owned guest checkout-link identifier.
x >= 0Show child attributes
Show child attributes
not_prepared, open, processing, paid, expired, revoked, non_payable Private Live Mode Stripe Checkout capability. Never log or persist it.
Present only in a Test Mode response. It is an explicit non-payable result, not a browser URL or checkout capability.
"non_payable"Server-owned proof of the promotion applied to the checkout session.
Show child attributes
Show child attributes
Live Mode bearer URL, returned only once in the first successful creation response. Treat as a secret.
Opaque server-owned Stripe Checkout Session identifier.
x >= 0curl --request POST \
--url https://api.batchrelay.com/v1/studios/{studio_id}/checkout-links \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"event_id": "<string>",
"recipient": {
"athlete_event_entry_id": "<string>",
"guardian_id": "<string>"
},
"sellable": {
"id": "<string>",
"quantity": 50,
"digital_configuration_id": "<string>",
"prepared_asset_assignment_ids": [
"<string>"
],
"variant_id": "<string>"
},
"customizable": false,
"expires_at": "2023-11-07T05:31:56Z",
"promotion": {
"code": "<string>",
"automatic": true,
"offer_id": "<string>"
}
}
'import requests
url = "https://api.batchrelay.com/v1/studios/{studio_id}/checkout-links"
payload = {
"event_id": "<string>",
"recipient": {
"athlete_event_entry_id": "<string>",
"guardian_id": "<string>"
},
"sellable": {
"id": "<string>",
"quantity": 50,
"digital_configuration_id": "<string>",
"prepared_asset_assignment_ids": ["<string>"],
"variant_id": "<string>"
},
"customizable": False,
"expires_at": "2023-11-07T05:31:56Z",
"promotion": {
"code": "<string>",
"automatic": True,
"offer_id": "<string>"
}
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
event_id: '<string>',
recipient: {athlete_event_entry_id: '<string>', guardian_id: '<string>'},
sellable: {
id: '<string>',
quantity: 50,
digital_configuration_id: '<string>',
prepared_asset_assignment_ids: ['<string>'],
variant_id: '<string>'
},
customizable: false,
expires_at: '2023-11-07T05:31:56Z',
promotion: {code: '<string>', automatic: true, offer_id: '<string>'}
})
};
fetch('https://api.batchrelay.com/v1/studios/{studio_id}/checkout-links', 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.batchrelay.com/v1/studios/{studio_id}/checkout-links",
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([
'event_id' => '<string>',
'recipient' => [
'athlete_event_entry_id' => '<string>',
'guardian_id' => '<string>'
],
'sellable' => [
'id' => '<string>',
'quantity' => 50,
'digital_configuration_id' => '<string>',
'prepared_asset_assignment_ids' => [
'<string>'
],
'variant_id' => '<string>'
],
'customizable' => false,
'expires_at' => '2023-11-07T05:31:56Z',
'promotion' => [
'code' => '<string>',
'automatic' => true,
'offer_id' => '<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$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.batchrelay.com/v1/studios/{studio_id}/checkout-links"
payload := strings.NewReader("{\n \"event_id\": \"<string>\",\n \"recipient\": {\n \"athlete_event_entry_id\": \"<string>\",\n \"guardian_id\": \"<string>\"\n },\n \"sellable\": {\n \"id\": \"<string>\",\n \"quantity\": 50,\n \"digital_configuration_id\": \"<string>\",\n \"prepared_asset_assignment_ids\": [\n \"<string>\"\n ],\n \"variant_id\": \"<string>\"\n },\n \"customizable\": false,\n \"expires_at\": \"2023-11-07T05:31:56Z\",\n \"promotion\": {\n \"code\": \"<string>\",\n \"automatic\": true,\n \"offer_id\": \"<string>\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
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.batchrelay.com/v1/studios/{studio_id}/checkout-links")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"event_id\": \"<string>\",\n \"recipient\": {\n \"athlete_event_entry_id\": \"<string>\",\n \"guardian_id\": \"<string>\"\n },\n \"sellable\": {\n \"id\": \"<string>\",\n \"quantity\": 50,\n \"digital_configuration_id\": \"<string>\",\n \"prepared_asset_assignment_ids\": [\n \"<string>\"\n ],\n \"variant_id\": \"<string>\"\n },\n \"customizable\": false,\n \"expires_at\": \"2023-11-07T05:31:56Z\",\n \"promotion\": {\n \"code\": \"<string>\",\n \"automatic\": true,\n \"offer_id\": \"<string>\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.batchrelay.com/v1/studios/{studio_id}/checkout-links")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"event_id\": \"<string>\",\n \"recipient\": {\n \"athlete_event_entry_id\": \"<string>\",\n \"guardian_id\": \"<string>\"\n },\n \"sellable\": {\n \"id\": \"<string>\",\n \"quantity\": 50,\n \"digital_configuration_id\": \"<string>\",\n \"prepared_asset_assignment_ids\": [\n \"<string>\"\n ],\n \"variant_id\": \"<string>\"\n },\n \"customizable\": false,\n \"expires_at\": \"2023-11-07T05:31:56Z\",\n \"promotion\": {\n \"code\": \"<string>\",\n \"automatic\": true,\n \"offer_id\": \"<string>\"\n }\n}"
response = http.request(request)
puts response.read_body{
"expires_at": "2023-11-07T05:31:56Z",
"id": "<string>",
"revocable": true,
"status": "active",
"checkout_intent_id": "<string>",
"currency": "USD",
"discount_cents": 1,
"gross_subtotal_cents": 1,
"guest_checkout_link_id": "<string>",
"net_subtotal_cents": 1,
"offer": {
"id": "<string>",
"revision_id": "<string>",
"code": "<string>",
"label": "<string>",
"revision": 2
},
"payment_state": "not_prepared",
"payment_url": "<string>",
"preview_status": "non_payable",
"promotion": {
"application": "checkout_session",
"currency": "USD",
"discount_type": "percent",
"discount_value": 123,
"offer_id": "<string>",
"revision_id": "<string>",
"code": "<string>",
"discount_cents": 1,
"gross_merchandise_cents": 1,
"net_merchandise_cents": 1
},
"share_url": "<string>",
"stripe_checkout_session_id": "<string>",
"subtotal_cents": 1
}{
"code": "<string>",
"docs_url": "<string>",
"error": "<string>",
"message": "<string>",
"request_id": "<string>"
}{
"code": "<string>",
"docs_url": "<string>",
"error": "<string>",
"message": "<string>",
"request_id": "<string>"
}{
"code": "<string>",
"docs_url": "<string>",
"error": "<string>",
"message": "<string>",
"request_id": "<string>"
}{
"code": "<string>",
"docs_url": "<string>",
"error": "<string>",
"message": "<string>",
"request_id": "<string>"
}{
"code": "<string>",
"docs_url": "<string>",
"error": "<string>",
"message": "<string>",
"request_id": "<string>"
}{
"code": "<string>",
"docs_url": "<string>",
"error": "<string>",
"message": "<string>",
"request_id": "<string>"
}