Execute Booking
curl --request POST \
--url https://api.privetag.com/api/b2a/execute_booking \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"activity_id": "<string>",
"user_email": "<string>",
"user_name": "<string>",
"booking_date": "<string>",
"num_adults": 123,
"num_children": 123,
"context_log_id": "<string>",
"special_requests": "<string>",
"webhook_url": "<string>"
}
'import requests
url = "https://api.privetag.com/api/b2a/execute_booking"
payload = {
"activity_id": "<string>",
"user_email": "<string>",
"user_name": "<string>",
"booking_date": "<string>",
"num_adults": 123,
"num_children": 123,
"context_log_id": "<string>",
"special_requests": "<string>",
"webhook_url": "<string>"
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
activity_id: '<string>',
user_email: '<string>',
user_name: '<string>',
booking_date: '<string>',
num_adults: 123,
num_children: 123,
context_log_id: '<string>',
special_requests: '<string>',
webhook_url: '<string>'
})
};
fetch('https://api.privetag.com/api/b2a/execute_booking', 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.privetag.com/api/b2a/execute_booking",
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([
'activity_id' => '<string>',
'user_email' => '<string>',
'user_name' => '<string>',
'booking_date' => '<string>',
'num_adults' => 123,
'num_children' => 123,
'context_log_id' => '<string>',
'special_requests' => '<string>',
'webhook_url' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-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.privetag.com/api/b2a/execute_booking"
payload := strings.NewReader("{\n \"activity_id\": \"<string>\",\n \"user_email\": \"<string>\",\n \"user_name\": \"<string>\",\n \"booking_date\": \"<string>\",\n \"num_adults\": 123,\n \"num_children\": 123,\n \"context_log_id\": \"<string>\",\n \"special_requests\": \"<string>\",\n \"webhook_url\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
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.privetag.com/api/b2a/execute_booking")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"activity_id\": \"<string>\",\n \"user_email\": \"<string>\",\n \"user_name\": \"<string>\",\n \"booking_date\": \"<string>\",\n \"num_adults\": 123,\n \"num_children\": 123,\n \"context_log_id\": \"<string>\",\n \"special_requests\": \"<string>\",\n \"webhook_url\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.privetag.com/api/b2a/execute_booking")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"activity_id\": \"<string>\",\n \"user_email\": \"<string>\",\n \"user_name\": \"<string>\",\n \"booking_date\": \"<string>\",\n \"num_adults\": 123,\n \"num_children\": 123,\n \"context_log_id\": \"<string>\",\n \"special_requests\": \"<string>\",\n \"webhook_url\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"booking_id": "<string>",
"status": "<string>",
"voucher": {
"code": "<string>",
"qr_url": "<string>",
"valid_until": "<string>"
},
"activity": {
"id": "<string>",
"title": "<string>",
"location": "<string>",
"check_in_instructions": "<string>"
},
"pricing": {
"unit_price": 123,
"total_guests": 123,
"subtotal": 123,
"discount": 123,
"total": 123,
"currency": "<string>"
},
"email_sent": true,
"email_sent_at": "<string>"
}
}B2A API
Execute Booking
Create a booking with automatic voucher delivery
POST
/
api
/
b2a
/
execute_booking
Execute Booking
curl --request POST \
--url https://api.privetag.com/api/b2a/execute_booking \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"activity_id": "<string>",
"user_email": "<string>",
"user_name": "<string>",
"booking_date": "<string>",
"num_adults": 123,
"num_children": 123,
"context_log_id": "<string>",
"special_requests": "<string>",
"webhook_url": "<string>"
}
'import requests
url = "https://api.privetag.com/api/b2a/execute_booking"
payload = {
"activity_id": "<string>",
"user_email": "<string>",
"user_name": "<string>",
"booking_date": "<string>",
"num_adults": 123,
"num_children": 123,
"context_log_id": "<string>",
"special_requests": "<string>",
"webhook_url": "<string>"
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
activity_id: '<string>',
user_email: '<string>',
user_name: '<string>',
booking_date: '<string>',
num_adults: 123,
num_children: 123,
context_log_id: '<string>',
special_requests: '<string>',
webhook_url: '<string>'
})
};
fetch('https://api.privetag.com/api/b2a/execute_booking', 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.privetag.com/api/b2a/execute_booking",
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([
'activity_id' => '<string>',
'user_email' => '<string>',
'user_name' => '<string>',
'booking_date' => '<string>',
'num_adults' => 123,
'num_children' => 123,
'context_log_id' => '<string>',
'special_requests' => '<string>',
'webhook_url' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-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.privetag.com/api/b2a/execute_booking"
payload := strings.NewReader("{\n \"activity_id\": \"<string>\",\n \"user_email\": \"<string>\",\n \"user_name\": \"<string>\",\n \"booking_date\": \"<string>\",\n \"num_adults\": 123,\n \"num_children\": 123,\n \"context_log_id\": \"<string>\",\n \"special_requests\": \"<string>\",\n \"webhook_url\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
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.privetag.com/api/b2a/execute_booking")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"activity_id\": \"<string>\",\n \"user_email\": \"<string>\",\n \"user_name\": \"<string>\",\n \"booking_date\": \"<string>\",\n \"num_adults\": 123,\n \"num_children\": 123,\n \"context_log_id\": \"<string>\",\n \"special_requests\": \"<string>\",\n \"webhook_url\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.privetag.com/api/b2a/execute_booking")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"activity_id\": \"<string>\",\n \"user_email\": \"<string>\",\n \"user_name\": \"<string>\",\n \"booking_date\": \"<string>\",\n \"num_adults\": 123,\n \"num_children\": 123,\n \"context_log_id\": \"<string>\",\n \"special_requests\": \"<string>\",\n \"webhook_url\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"booking_id": "<string>",
"status": "<string>",
"voucher": {
"code": "<string>",
"qr_url": "<string>",
"valid_until": "<string>"
},
"activity": {
"id": "<string>",
"title": "<string>",
"location": "<string>",
"check_in_instructions": "<string>"
},
"pricing": {
"unit_price": 123,
"total_guests": 123,
"subtotal": 123,
"discount": 123,
"total": 123,
"currency": "<string>"
},
"email_sent": true,
"email_sent_at": "<string>"
}
}Execute Booking
This endpoint creates a real booking and sends a voucher email within 30 seconds. 99% success rate with live inventory sync.
Use This Endpoint When
User confirms selection
- “Book this one”
- “Reserve for tomorrow”
- “I want the spa package”
After recommendation
- User selected from
/recommendresults - User chose from
/inventorylistings
Request
string
required
Activity ID from
/recommend or /inventory responsestring
required
Email address for voucher delivery
string
required
Guest name for the voucher
string
required
ISO 8601 date format (e.g.,
2025-12-15)number
required
Number of adults (1-20)
number
default:"0"
Number of children
string
Recommended: Pass the
log_id from /recommend response for conversion tracking and feedback loopstring
Any special requests or notes
string
Optional URL to receive booking status callbacks
Response
boolean
Whether the booking was created successfully
object
Show Properties
Show Properties
string
Unique booking identifier
string
One of:
confirmed, pending, processingobject
object
object
boolean
Whether voucher email was sent
string
Timestamp of email delivery
Examples
Basic Booking
curl -X POST https://api.privetag.com/api/b2a/execute_booking \
-H "x-api-key: pk_a1b2c3..." \
-H "Content-Type: application/json" \
-d '{
"activity_id": "act_abc123",
"user_email": "guest@example.com",
"user_name": "John Doe",
"booking_date": "2025-12-15",
"num_adults": 2,
"context_log_id": "ctx_xyz789"
}'
import requests
response = requests.post(
"https://api.privetag.com/api/b2a/execute_booking",
headers={
"x-api-key": "pk_a1b2c3...",
"Content-Type": "application/json"
},
json={
"activity_id": "act_abc123",
"user_email": "guest@example.com",
"user_name": "John Doe",
"booking_date": "2025-12-15",
"num_adults": 2,
"context_log_id": "ctx_xyz789"
}
)
booking = response.json()
print(f"Booking confirmed: {booking['data']['booking_id']}")
print(f"Voucher code: {booking['data']['voucher']['code']}")
const response = await fetch('https://api.privetag.com/api/b2a/execute_booking', {
method: 'POST',
headers: {
'x-api-key': 'pk_a1b2c3...',
'Content-Type': 'application/json'
},
body: JSON.stringify({
activity_id: 'act_abc123',
user_email: 'guest@example.com',
user_name: 'John Doe',
booking_date: '2025-12-15',
num_adults: 2,
context_log_id: 'ctx_xyz789'
})
});
const booking = await response.json();
console.log(`Booking confirmed: ${booking.data.booking_id}`);
Family Booking with Children
{
"activity_id": "act_abc123",
"user_email": "family@example.com",
"user_name": "Smith Family",
"booking_date": "2025-12-20",
"num_adults": 2,
"num_children": 3,
"special_requests": "One child is under 3 years old",
"context_log_id": "ctx_xyz789"
}
With Webhook Callback
{
"activity_id": "act_abc123",
"user_email": "guest@example.com",
"user_name": "John Doe",
"booking_date": "2025-12-15",
"num_adults": 2,
"webhook_url": "https://your-server.com/webhooks/privetag"
}
Response Example
{
"success": true,
"data": {
"booking_id": "bkg_h7j9k2m4",
"status": "confirmed",
"voucher": {
"code": "PVT-2025-ABC123",
"qr_url": "https://cdn.privetag.com/vouchers/qr/bkg_h7j9k2m4.png",
"valid_until": "2025-12-15T23:59:59Z"
},
"activity": {
"id": "act_abc123",
"title": "Safari World Bangkok",
"location": "99 Panyaintra Road, Sam Wa Tawan Tok, Bangkok",
"check_in_instructions": "Show QR code at main entrance ticket counter"
},
"pricing": {
"unit_price": 1500,
"total_guests": 2,
"subtotal": 3000,
"discount": 0,
"total": 3000,
"currency": "THB"
},
"email_sent": true,
"email_sent_at": "2025-12-10T14:30:15Z"
}
}
Booking Flow
Ground Truth Feedback Loop
Why pass
context_log_id?When a user visits the venue and scans their QR code, we connect:- The original recommendation context
- Which activity was booked
- Whether they actually visited
Webhook Events
If you provide awebhook_url, you’ll receive callbacks for:
| Event | Description |
|---|---|
booking_confirmed | Booking successfully created |
voucher_delivered | Email sent to user |
qr_verified | User visited venue (Ground Truth) |
booking_cancelled | Booking was cancelled |
{
"event": "qr_verified",
"booking_id": "bkg_h7j9k2m4",
"activity_id": "act_abc123",
"verified_at": "2025-12-15T10:30:00Z",
"context_log_id": "ctx_xyz789"
}
Error Responses
| Code | Description |
|---|---|
ACTIVITY_NOT_FOUND | Activity ID doesn’t exist |
ACTIVITY_UNAVAILABLE | Activity not available on requested date |
INVALID_DATE | Booking date is in the past or too far ahead |
INVENTORY_EXHAUSTED | No more slots available |
INVALID_EMAIL | Email format is invalid |
BOOKING_LIMIT_EXCEEDED | Maximum guests per booking exceeded |
Error Response Example
{
"success": false,
"error": "Activity not available",
"code": "ACTIVITY_UNAVAILABLE",
"details": "Safari World is closed on Mondays. Available dates: Tue-Sun"
}
Best Practices
Always pass context_log_id
Always pass context_log_id
This enables the Ground Truth feedback loop, improving recommendations over time.
Handle webhook callbacks
Handle webhook callbacks
Use webhooks to update your UI in real-time when voucher is delivered or QR is scanned.
Validate dates client-side
Validate dates client-side
Check that booking_date is not in the past and is within the activity’s operating days.
Confirm with user before booking
Confirm with user before booking
Bookings are real and charged. Always confirm details with the user before calling this endpoint.
Next Steps
Check Inventory
View real-time availability before booking
Webhooks
Set up webhook callbacks for booking events
⌘I