Salesbooth API
Deal infrastructure for AI commerce. Build integrations, automate deal flows, and embed commerce into any surface with our REST API.
Overview
The Salesbooth API is a RESTful JSON API. All requests and responses use application/json.
Base URL
https://api.salesbooth.com/v1/
Response Format
Success (200 / 201)
{
"error": false,
"success": true,
"data": { ... }
}
Error
{
"error": true,
"code": "validation_error.invalid_fields",
"category": "validation_error",
"message": "Name is required",
"recovery": {
"action": "fix_request",
"retryable": false
},
"ref": "abc123",
"details": { ... }
}
Authentication
Authenticate requests with an API key sent as a Bearer token or via the X-API-Key header. All secret API keys should be sent in request headers — query-parameter auth (?api_key=) is deprecated for secret keys and will be rejected in a future release (see Security Notice below).
Bearer Token (recommended)
curl https://api.salesbooth.com/v1/deals \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Alternative Header
curl https://api.salesbooth.com/v1/deals \
-H "X-API-Key: sb_test_example_key_do_not_use"
Key Types
Salesbooth issues three distinct key types. Choosing the right type for each context is important for security.
Keys include a two-letter region component (au, eu, us) that routes requests to the correct regional data store. The full format is sb_{type}_{region}_{random}, for example sb_live_au_a1b2c3d4....
| Prefix | Type | Environment | Notes |
sb_live_{region}_* |
Secret — live |
Production |
Keep private. Server-side only. Full API access within granted scopes. |
sb_test_{region}_* |
Secret — test |
Sandbox |
Keep private. Server-side only. Operates against isolated sandbox data; no real money moves. |
sb_pub_{region}_* |
Publishable |
Production |
Safe for browser embedding. Used by the <salesbooth-deal> widget. Scoped to widget operations only (products:read, customers:write, deals:write, agent:negotiate). Auto-generated when a widget config is created. |
Publishable keys and widgets: When you create a widget config via POST /api/v1/widget-config, the response includes a publishable_key (sb_pub_{region}_*). Pass this as the api-key attribute on the <salesbooth-deal> element. Never use a secret key (sb_live_{region}_* or sb_test_{region}_*) in client-side code.
Security Notice: Passing secret API keys (sb_live_{region}_*, sb_test_{region}_*) via the ?api_key= query parameter is deprecated and will be rejected in a future release. Query parameters appear in server logs, browser history, and referrer headers — use header-based authentication instead.
Tenants can opt in to immediate enforcement by setting enforce_header_auth to 1 in tenant settings.
Note: Publishable keys (sb_pub_{region}_*) used by widget public endpoints (/api/v1/widget-config, /api/v1/widget-intelligence, /api/v1/ab-tests/resolve) are not affected by this deprecation. These endpoints handle ?api_key= in their own code paths, independent of the standard authentication flow, and must continue to use query parameter auth for browser-embedded widgets.
CORS
API keys can be restricted to specific origins. Set allowed_origins when creating a key to limit which domains can use it from the browser.
Scopes & Permissions
API keys are scoped to specific resources and operations. Assign only the scopes your integration needs.
| Scope | Description |
* | Full access — all resources, all operations |
*:read | Read-only access to all resources |
deals:read | Read deals, line items, and deal audit trail |
deals:write | Create, update, and manage deals and deal templates |
deals:sign | Sign and countersign deals |
customers:read | Read customer records and customer audit trail |
customers:write | Create and update customers |
products:read | Read products, pricing, and product audit trail |
products:write | Create and update products |
contracts:read | Read contracts and contract audit trail |
contracts:write | Create, sign, and manage contracts |
webhooks:read | List webhooks and delivery history |
webhooks:write | Register and manage webhooks |
agent:* | Full agent access — discover, negotiate, and execute deals |
agent:discover | Discover available deals and tenant catalogue |
agent:negotiate | Negotiate deal terms on behalf of a buyer |
agent:execute | Execute and accept deals |
intelligence:read | Read intelligence configuration and AI settings |
intelligence:write | Update intelligence configuration and AI settings |
billing:read | Read credit balance and ledger |
billing:write | Top up credits and manage billing |
trust:read | Read trust level and progress metrics |
trust:write | Write trust signals and submit fraud reports |
staff:read | Read staff members and availability |
staff:write | Create and update staff members |
team:read | Read team members |
team:write | Invite, update, and remove team members |
bookings:read | Read bookings and appointments |
bookings:write | Create and manage bookings |
queue:read | Read job queue status and dead-letter queue |
queue:write | Retry dead-lettered jobs and manage queue |
audit:export | Export audit trail compliance packages |
sandbox:read | Read sandbox environment status |
sandbox:write | Reset, seed, and simulate webhooks in sandbox mode |
sites:read | Read sites and pages |
sites:write | Create and manage sites, pages, and suggestions |
delegations:read | Read agent delegations |
delegations:write | Create and manage agent delegations |
activity:read | Read activity feed and stream events |
activity:write | Write activity entries |
search:read | Search across deals, customers, and products |
admin:read | Read tenant settings, business profile, and analytics settings |
admin:write | Write tenant settings, business profile, and analytics settings |
admin | Administrative operations — encryption rotation, cache management. Restrict to secure server-side keys only. |
Rate Limiting
Salesbooth enforces a three-tier rate limiting system. Every request is checked against all three tiers simultaneously; the most restrictive limit that fires determines the response.
Tier 1 — Per-API-Key Limit
Each API key has a configurable per-minute limit (default: 1,000 req/min, sliding window). Agent keys receive a trust-level multiplier on top of the configured limit:
| Trust Level | Multiplier | Effective Limit (default key) |
| L0 — Untrusted | 0.5× | 500 req/min |
| L1 — Provisional | 1.0× | 1,000 req/min |
| L2 — Established | 2.0× | 2,000 req/min |
| L3 — Trusted | 5.0× | 5,000 req/min |
| L4 — Verified Partner | 10.0× | 10,000 req/min |
Multipliers apply to agent API keys only. Regular user keys always use the configured limit unchanged. In addition, each key gets a burst allowance of 25% of its per-minute limit, refilled at 1 token per second.
Tier 2 — Per-IP Limit
| Request Type | Limit | Window |
| Authenticated requests | 5,000 req/hr | Sliding hourly window |
| Unauthenticated requests | 100 req/hr | Sliding hourly window |
Tier 3 — Global Circuit Breaker
A platform-wide circuit breaker fires at 50,000 req/min across all tenants. When tripped, the API returns 503 Service Unavailable (not 429) with Retry-After. This protects all tenants during traffic spikes.
Response Headers
| Header | Description |
X-RateLimit-Limit | Limit for the tier that was checked (after trust multiplier) |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
X-RateLimit-Policy | Which tier triggered the limit: global, ip, key, endpoint, or burst |
X-Trust-Level | Agent key trust level (0–4), included when a trust multiplier applied |
X-RateLimit-Multiplier | Trust multiplier applied to the key limit (e.g. 2.0) |
Retry-After | Seconds to wait before retrying (present on 429 and 503) |
HTTP Status Codes
| Status | Meaning | When to retry |
429 | Per-key or per-IP limit exceeded | After Retry-After seconds with exponential backoff |
503 | Global circuit breaker triggered | After Retry-After seconds; all tenants affected |
Retry Pattern
async function callWithBackoff(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const res = await fn();
if (res.status !== 429 && res.status !== 503) return res;
const retryAfter = parseInt(res.headers.get('Retry-After') || '5', 10);
const jitter = Math.random() * 1000;
await new Promise(r => setTimeout(r, retryAfter * 1000 + jitter));
}
throw new Error('Max retries exceeded');
}
MCP endpoint rate limits: The POST /api/v1/mcp endpoint shares the same per-key limit. Each JSON-RPC call (including every tools/call invocation) counts as one request. Agents that issue many tools/call requests in a single workflow session can exhaust this quota quickly — implement backoff on 429 responses and consider batching where possible.
Error Handling
The API uses standard HTTP status codes. Every error response includes a machine-readable code, a human-readable message, and a recovery object with action, retryable, and a hint.
Error code format: The code field uses dotted lowercase notation: category.specific_code (e.g. validation_error.invalid_fields, conflict.stale_version, billing.trust_ceiling_exceeded).
Recommendation: Use the category field (always present and stable) for programmatic error handling instead of matching exact code strings. The stable category values are: validation_error, authentication_error, authorization_error, not_found, conflict, rate_limited, billing, transient_error, internal_error.
Error Response Format
{
"error": true,
"code": "validation_error.invalid_fields",
"message": "Name is required",
"category": "validation_error",
"recovery": {
"action": "fix_request",
"retryable": false,
"hint": "Check the details.fields object for specific field errors."
},
"details": {
"fields": {
"name": { "code": "required", "message": "Name is required" }
}
}
}
Standard HTTP Errors
| Status | Code | Description |
400 | validation_error.bad_request | Missing or invalid parameters |
400 | validation_error.invalid_fields | Request body failed validation — check details.fields |
401 | authentication_error.invalid_credentials | Missing or invalid API key |
403 | authorization_error.insufficient_scope | Valid key but insufficient permissions or missing scope |
403 | authorization_error.cors_origin_denied | Request origin not in key’s allowed origins |
404 | not_found | Resource does not exist or you lack access |
405 | method_not_allowed | HTTP method not supported for this endpoint |
429 | rate_limited | Too many requests — check X-RateLimit-Reset header |
500 | internal_error | Internal server error — safe to retry with backoff |
503 | transient_error | Transient outage or circuit breaker open — retry after recovery.retry_after_seconds |
Optimistic Locking (412)
Resources that support concurrent updates use optimistic locking. The current resource version is returned in the ETag response header. To update, send the version in an If-Match header. A version mismatch returns 412 Precondition Failed with the current resource state so you can merge and retry.
Example — version conflict on PATCH deals
# First, fetch the current version
curl https://api.salesbooth.com/v1/deals?id=deal_abc123 \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
# Response includes: ETag: W/"5"
# Then update with the version
curl -X PATCH "https://api.salesbooth.com/v1/deals?id=deal_abc123" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-H "If-Match: W/\"5\"" \
-d '{"title": "Updated Title"}'
# If another request updated the deal first, you get:
# 412 Precondition Failed
# { "error": true, "code": "conflict.stale_version", "category": "conflict",
# "message": "Resource has been modified by another request. Refresh and retry.",
# "recovery": { "action": "refetch_and_retry", "retryable": true,
# "hint": "Read the current resource version from response data, merge your changes, and retry with the new ETag." },
# "data": { <current resource state> } }
Domain-Specific Error Codes
| Status | Code | Description | Resolution |
412 |
conflict.stale_version |
Optimistic locking conflict — resource was modified between your read and write |
Re-fetch the resource, apply your changes, and retry with the new ETag value in If-Match. The current resource state is included in the data field. |
402 |
billing.insufficient_credit |
Your credit balance is too low to complete the operation |
Top up via POST /api/v1/credits or the dashboard, then retry. details.shortfall shows the amount needed. |
402 |
billing.trust_ceiling_exceeded |
Monthly auto top-up ceiling reached for your trust level |
Wait until the 1st of next month, or upgrade your trust level. details.ceiling and details.monthly_used are included. |
403 |
trust_cap_exceeded (category: authorization_error) |
Agent transaction cap exceeded for current trust level (L0: $0, L1: $500, L2: $5,000, L3+: unlimited) |
Complete more deals to earn trust score and advance to a higher trust level. details.transaction_cap shows your current limit. |
403 |
DELEGATION_BUDGET_EXCEEDED (category: authorization_error) |
Proposed deal value exceeds the remaining delegation spending limit |
Propose a lower deal value within details.remaining_budget, or request a higher delegation limit from the authorizing tenant. |
429 |
spending_limit_exceeded (category: rate_limited) |
Delegation per-transaction, daily, or monthly spending limit reached |
Wait for the limit to reset (recovery.retry_after_seconds = 86400). Check details.remaining_daily and details.remaining_monthly. |
Retryable vs. Non-Retryable
Every error includes recovery.retryable. When true, the recovery.retry_after_seconds field tells you how long to wait before retrying. Implement exponential backoff for 503 and 429 responses.
Error Codes Reference
Complete taxonomy of all error codes returned by the API, grouped by category. Use the category field for programmatic handling — it is stable and will not change. The code field provides specific detail within a category.
Recommended pattern: Branch on category, not code. Future releases may add new code values within an existing category, but new categories will always be announced in the changelog.
Authentication Errors (401)
| Status | Code | Description | Recovery |
401 | authentication_error.invalid_credentials | Missing, malformed, or expired API key | Verify the Authorization: Bearer <key> header. Generate a new key if expired. |
401 | UNAUTHORIZED LEGACY | Authentication failed (legacy format) | Same as above. Prefer checking category === 'authentication_error'. |
Authorization Errors (403)
| Status | Code | Description | Recovery |
403 | authorization_error.insufficient_scope | API key lacks the required scope for this operation | Issue a new key with the required scope, or use a key that already has it. See Scopes. |
403 | FORBIDDEN LEGACY | Access denied (legacy format) | Check key scopes. |
403 | INSUFFICIENT_SCOPE LEGACY | Insufficient API key scope | Add the required scope to your API key. |
403 | CORS_ORIGIN_DENIED | Request origin is not in the key’s allowed origins list | Add the origin to your API key’s allowed origins in the developer settings. |
403 | trust_cap_exceeded | Agent transaction exceeds trust level spending cap (L0: $0, L1: $500, L2: $5 000) | Complete more deals to advance trust levels, or use a higher trust-level agent. |
403 | DELEGATION_BUDGET_EXCEEDED | Deal value exceeds remaining delegation budget | Propose a value within details.remaining_budget, or request a higher delegation limit. |
Validation Errors (400)
| Status | Code | Description | Recovery |
400 | validation_error.invalid_fields | One or more fields failed validation — see details.fields | Fix each field listed in details.fields. Each entry has a code (required, invalid, too_long, etc.) and a human message. |
400 | validation_error.bad_request | Request is structurally invalid (missing required parameter, wrong type) | Read message for specific guidance on what is missing or wrong. |
400 | validation_error.body_too_large | Request body exceeds the 1 MB limit | Reduce the request body size. |
400 | validation_error.method_not_allowed | Wrong HTTP method for this endpoint | Check the Allow response header for the allowed methods. |
400 | validation_error.precondition_required | If-Match header is required but missing | Fetch the resource to get its current ETag, then include it as If-Match: W/"<n>". |
413 | validation_error.body_too_large | Request body exceeds maximum size | Reduce request body to under 1 MB. |
405 | METHOD_NOT_ALLOWED LEGACY | HTTP method not supported | Check the Allow header. |
428 | validation_error.precondition_required | If-Match header is required for this mutating operation | Include If-Match: W/"<version>" from a prior GET’s ETag header. |
Not Found (404)
| Status | Code | Description | Recovery |
404 | not_found | Resource does not exist, has been deleted, or belongs to another tenant | Verify the ID is correct. Check that you’re using the right API key for this tenant. |
404 | NOT_FOUND LEGACY | Resource not found (legacy format) | Same as above. |
Conflict Errors (409 / 412)
| Status | Code | Description | Recovery |
409 | conflict.stale_version | Optimistic lock conflict — resource was modified between your read and write | Re-fetch resource, merge changes, retry with new ETag in If-Match. Current resource state is in data. |
409 | conflict.deal_already_closed | Operation not permitted on a closed deal | Create a new deal. |
409 | conflict.idempotency_key_reused | Idempotency key was already used with different request body | Use a new unique idempotency key. If the original request succeeded, fetch the resource to check its state. |
412 | conflict.stale_version | If-Match version mismatch — someone else updated the resource first | Re-fetch resource (current state in data), merge, and retry with new ETag. |
Billing Errors (402)
| Status | Code | Description | Recovery |
402 | billing.insufficient_credit | Credit balance too low to complete the operation | Top up via POST /api/v1/credits. details.shortfall shows the amount needed. |
402 | billing.trust_ceiling_exceeded | Monthly auto top-up ceiling reached for your trust level | Wait until the 1st of next month, or upgrade your trust level. |
Rate Limiting (429)
| Status | Code | Description | Recovery |
429 | rate_limited | Too many requests — global rate limit exceeded | Wait recovery.retry_after_seconds (default 60 s). Implement exponential backoff. |
429 | RATE_LIMIT_EXCEEDED LEGACY | Too many requests (legacy format) | Check X-RateLimit-Reset header. |
429 | spending_limit_exceeded | Delegation per-transaction, daily, or monthly limit reached | Wait for limit reset. Check details.remaining_daily and details.remaining_monthly. |
Server & Transient Errors (500 / 503)
| Status | Code | Description | Recovery |
500 | internal_error | Unexpected server error. The error ref field contains a trace ID for support. | Contact support with the ref value. Safe to retry with exponential backoff if idempotent. |
503 | transient_error | Temporary outage or circuit breaker open | Retry after recovery.retry_after_seconds (default 5 s). Max 3 retries with exponential backoff. |
500 | SERVER_ERROR LEGACY | Internal error (legacy format) | Same as above. |
Error Handling — JavaScript (Fetch)
JavaScript
async function apiCall(path, options = {}) {
const res = await fetch(`https://api.salesbooth.com/v1/${path}`, {
...options,
headers: {
'Authorization': 'Bearer ' + API_KEY,
'Content-Type': 'application/json',
...(options.headers || {}),
},
});
const data = await res.json();
if (data.error) {
// Branch on category (stable) not code (may change)
switch (data.category) {
case 'authentication_error':
// Refresh or prompt for re-authentication
throw new Error('Authentication failed: ' + data.message);
case 'authorization_error':
throw new Error('Permission denied: ' + data.message);
case 'validation_error':
// data.details.fields has per-field errors
throw new Error('Validation failed: ' + data.message);
case 'not_found':
throw new Error('Resource not found: ' + data.message);
case 'conflict':
if (data.code === 'conflict.stale_version') {
// Merge data.data (current state) with your changes and retry
throw new Error('Version conflict — refetch and retry');
}
throw new Error('Conflict: ' + data.message);
case 'rate_limited':
// Retry after recovery.retry_after_seconds
const retryAfter = data.recovery?.retry_after_seconds || 60;
await new Promise(r => setTimeout(r, retryAfter * 1000));
return apiCall(path, options); // retry once
case 'transient_error':
// Short retry
await new Promise(r => setTimeout(r, (data.recovery?.retry_after_seconds || 5) * 1000));
return apiCall(path, options);
default:
throw new Error(data.message || 'An error occurred (ref: ' + data.ref + ')');
}
}
return data.data;
}
Error Handling — curl
curl
# All errors return a consistent JSON body:
curl "https://api.salesbooth.com/v1/deals?id=nonexistent" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
# 404 response:
# {
# "error": true,
# "code": "not_found",
# "category": "not_found",
# "message": "Resource not found",
# "recovery": {
# "action": "check_resource_id",
# "retryable": false,
# "hint": "Verify the resource ID exists and you have access to it."
# },
# "ref": "trace_abc123" <-- include this in support requests
# }
First Integration
The shortest path to a working integration. These four API calls are all you need to create a deal and collect a payment — no Intelligence API, negotiations, or webhooks required. Once this works, head to the SDK Quick Start for a more complete walkthrough.
Step 1 — Create a Product
curl -X POST https://api.salesbooth.com/v1/products \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"name": "Pro Plan",
"price": 99.00,
"type": "service"
}'
# Save the returned id: prod_xxxxx
Step 2 — Create a Customer
curl -X POST https://api.salesbooth.com/v1/customers \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Smith",
"email": "jane@example.com",
"company": "Acme Corp"
}'
# Save the returned id: cust_xxxxx
Step 3 — Create a Deal and Add a Line Item
# Create the deal
curl -X POST https://api.salesbooth.com/v1/deals \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cust_xxxxx",
"title": "Pro Plan — Jane Smith",
"currency": "USD",
"tax_rate": 0.10
}'
# Save the returned id: deal_xxxxx
# Add a line item
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=add_item" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"product_id": "prod_xxxxx",
"name": "Pro Plan",
"quantity": 1,
"unit_price": 99.00
}'
# Transition to in_progress so the customer can pay
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=transition&status=in_progress" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Step 4 — Collect Payment
curl -X POST https://api.salesbooth.com/v1/payments?action=create-intent \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"deal_id": "deal_xxxxx",
"amount": 108.90,
"currency": "USD"
}'
# Returns a Stripe client_secret — pass to Stripe.js on your frontend to complete payment
That's it. You now have a complete deal flow: product → customer → deal → payment. For embeddable widgets, AI deal scoring, webhooks, negotiations, and more, continue to the SDK Quick Start below.
SDK Quick Start
From zero to a live deal widget in 5 minutes. This walkthrough installs the SDK, creates a product, creates a deal, and embeds the deal widget on your page.
Step 1 — Install
CDN (browser)
<script src="https://salesbooth.com/sdk/v1/salesbooth.js"></script>
Node.js / CommonJS (npm)
# Install from npm
npm install @salesbooth/node
const { SalesBooth } = require('@salesbooth/node');
const sb = new SalesBooth({ apiKey: 'sb_test_example_key_do_not_use' });
Step 2 — Create a Product
const product = await sb.products.create({
name: 'Pro Plan',
price: 99.00,
type: 'service',
description: 'Monthly pro subscription'
});
console.log('Product:', product.product_id); // prod_xxxxx
Step 3 — Create a Customer & Deal
Initialize + Create a Deal
const { SalesBooth } = require('@salesbooth/node');
const sb = new SalesBooth({ apiKey: 'sb_test_example_key_do_not_use' });
// Create a customer
const customer = await sb.customers.create({
name: 'Jane Smith',
email: 'jane@example.com',
company: 'Acme Corp'
});
// Create a deal with a line item
const deal = await sb.deals.create({
title: 'Pro Plan — Jane Smith',
customer_id: customer.customer_id,
currency: 'USD',
tax_rate: 0.10
});
await sb.deals.addItem(deal.deal_id, {
product_id: 'prod_xxxxx',
quantity: 1,
unit_price: 499.00
});
console.log('Deal created:', deal.deal_id);
SDK Resources: The SDK exposes sb.deals, sb.customers, sb.products, sb.contracts, sb.webhooks, sb.negotiations, sb.templates, sb.intelligence, sb.delegations, sb.configuration, sb.productRules, sb.savedConfigs, sb.widgets, and sb.analytics. Each resource provides list(), get(), create(), update(), and resource-specific methods.
Step 4 — Add a Line Item & Transition
await sb.deals.addItem(deal.deal_id, {
product_id: product.product_id,
quantity: 1,
unit_price: 99.00
});
// Move the deal from draft to in_progress
await sb.deals.transition(deal.deal_id, 'in_progress');
console.log('Deal ready:', deal.deal_id);
Step 5 — Embed the Deal Widget
The deal widget lets buyers configure products, negotiate, and sign — all embedded in your site with a single script tag.
Create a widget config (server-side)
curl -X POST https://api.salesbooth.com/v1/widget-config \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"site_id": "site_xxxxx",
"title": "Get Pro Plan",
"currency": "USD",
"products": "prod_xxxxx"
}'
# Response includes: { "data": { "widget_id": "wgt_xxxxx", "publishable_key": "sb_pub_xxxxx" } }
Embed in your HTML
<!-- 1. Load the widget SDK -->
<script src="https://salesbooth.com/sdk/v1/salesbooth-widget.js"
crossorigin="anonymous"></script>
<!-- 2. Place the custom element anywhere in your page -->
<salesbooth-deal api-key="sb_pub_xxxxx"></salesbooth-deal>
<!-- 3. Listen for deal events -->
<script>
document.querySelector('salesbooth-deal').addEventListener('salesbooth:deal-created', (e) => {
console.log('Deal created!', e.detail.dealId);
});
</script>
Core integration complete. Steps 1–5 cover the most common use case. The steps below show optional advanced features — you can skip them on your first integration and return when you need them.
Step 6 — Score a Deal with the Intelligence API (optional)
const { SalesBooth } = require('@salesbooth/node');
const sb = new SalesBooth({ apiKey: 'sb_test_example_key_do_not_use' });
// Get AI score for a deal
const score = await sb.intelligence.scoreDeal('deal_abc123');
console.log(`Score: ${score.score}/100 (${score.confidence} confidence)`);
// Get pricing suggestions
const suggestion = await sb.intelligence.getPricingSuggestion('deal_abc123');
console.log(`Suggested price: ${suggestion.suggested_price} (win rate: ${suggestion.win_rate_at_suggested})`);
// Get risk assessment
const risk = await sb.intelligence.assessRisk('deal_abc123');
if (risk.overall_risk !== 'low') {
const highRisk = risk.factors.filter(f => f.severity === 'high');
highRisk.forEach(f => console.warn(`Risk: ${f.factor} — ${f.mitigation}`));
}
// Get pipeline forecast for next 90 days
const forecast = await sb.intelligence.forecastPipeline({ period: '90d' });
console.log(`90-day weighted pipeline: $${forecast.weighted_pipeline.toLocaleString()}`);
Step 7 — Negotiate Deal Terms (optional)
const { SalesBooth } = require('@salesbooth/node');
const sb = new SalesBooth({ apiKey: 'sb_test_example_key_do_not_use' });
// Propose terms to a merchant
await sb.negotiations.propose('deal_abc123', {
proposed_terms: { discount_percent: 12, payment_terms: 'net_30' },
message: 'Can we agree on 12% for a 3-year commitment?',
expires_at: '2026-03-19T00:00:00Z'
});
// Get AI suggestions before countering
const suggestions = await sb.negotiations.suggest('deal_abc123');
const balanced = suggestions.data.suggestions.find(s => s.strategy === 'balanced');
console.log('AI suggests:', balanced.proposed_terms, `(confidence: ${balanced.confidence})`);
// Counter with AI-suggested terms
await sb.negotiations.counter('deal_abc123', {
proposed_terms: balanced.proposed_terms,
message: balanced.rationale
});
// Accept the other party's latest terms
await sb.negotiations.accept('deal_abc123');
// Get full negotiation history
const history = await sb.negotiations.history('deal_abc123');
console.log(`${history.data.total_rounds} rounds, final status: ${history.data.status}`);
Step 8 — Set Up a Webhook Listener (optional)
const crypto = require('crypto');
const { SalesBooth } = require('@salesbooth/node');
const sb = new SalesBooth({ apiKey: 'sb_test_example_key_do_not_use' });
// Register a webhook endpoint
const webhook = await sb.webhooks.create({
url: 'https://myapp.com/webhooks/salesbooth',
events: ['deal.closed', 'deal.payment_received', 'subscription.renewed', 'negotiation.accepted'],
description: 'Production webhook'
});
console.log('Webhook registered:', webhook.webhook_id);
console.log('Signing secret (save this):', webhook.secret);
// Verify incoming events (server-side)
function verifyAndParseWebhook(rawBody, sig, timestamp, secret) {
const age = Math.floor(Date.now() / 1000) - parseInt(timestamp, 10);
if (age > 300) throw new Error('Stale event');
const expected = 'v1=' + crypto.createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`, 'utf8').digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)))
throw new Error('Invalid signature');
return JSON.parse(rawBody);
}
// Handle deal.closed
function handleEvent(event) {
switch (event.event) {
case 'deal.closed':
console.log(`Deal ${event.data.deal_id} closed — revenue: ${event.data.total}`);
break;
case 'negotiation.accepted':
console.log(`Negotiation accepted: ${JSON.stringify(event.data.final_terms)}`);
break;
case 'subscription.renewed':
console.log(`Subscription renewed: $${event.data.total_amount} ${event.data.currency}`);
break;
}
}
Step 9 — List Products and Create a Deal (optional)
const { SalesBooth } = require('@salesbooth/node');
const sb = new SalesBooth({ apiKey: 'sb_test_example_key_do_not_use' });
// List available products
const products = await sb.products.list({ limit: 10 });
const product = products.products.find(p => p.name === 'Pro Plan');
console.log('Product:', product.product_id, '— price:', product.price);
// Create a customer
const customer = await sb.customers.create({
name: 'Jane Smith',
email: 'jane@example.com',
company: 'Acme Corp'
});
// Create deal, add item, and transition
const deal = await sb.deals.create({
title: 'Pro Plan — Jane Smith',
customer_id: customer.customer_id,
currency: 'USD',
tax_rate: 0.10
});
await sb.deals.addItem(deal.deal_id, {
product_id: product.product_id,
quantity: 5,
unit_price: product.price
});
// Apply discount and transition
await sb.deals.applyDiscount(deal.deal_id, { type: 'percentage', value: 10 });
await sb.deals.transition(deal.deal_id, 'in_progress');
console.log(`Deal ${deal.deal_id} ready — total: $${deal.total}`);
Event Handling
sb.on('error', (err) => console.error(err.code, err.message));
sb.on('offline', () => console.log('Offline — requests will queue'));
sb.on('online', () => console.log('Back online — flushing queue'));
Python Examples
The Salesbooth REST API is language-agnostic. The following examples use the requests library.
Install
pip install requests
Python — Create a customer and deal
import requests
API_KEY = "sb_test_example_key_do_not_use"
BASE = "https://api.salesbooth.com/v1"
HDR = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
# Create a customer
r = requests.post(f"{BASE}/customers", headers=HDR, json={
"name": "Jane Smith",
"email": "jane@example.com",
"company": "Acme Corp"
})
r.raise_for_status()
customer = r.json()["data"]["customer"]
print("Customer:", customer["customer_id"])
# Create a deal with idempotency
r = requests.post(f"{BASE}/deals", headers={**HDR, "Idempotency-Key": "order-20260317-001"}, json={
"customer_id": customer["customer_id"],
"currency": "USD",
"tax_rate": 0.10
})
r.raise_for_status()
deal = r.json()["data"]["deal"]
print("Deal:", deal["deal_id"])
# Add a line item
r = requests.post(f"{BASE}/deals?id={deal['deal_id']}&action=add_item", headers=HDR, json={
"product_id": "prod_xxxxx",
"quantity": 1,
"unit_price": 499.00
})
r.raise_for_status()
print("Line item added")
# Transition to in_progress
r = requests.post(f"{BASE}/deals?id={deal['deal_id']}&action=transition&status=in_progress", headers=HDR)
r.raise_for_status()
print("Deal transitioned:", r.json()["data"]["status"])
Python — Verify a webhook signature
import hashlib, hmac, time
from flask import Flask, request, abort
app = Flask(__name__)
WEBHOOK_SECRET = "your_webhook_signing_secret"
TOLERANCE = 300 # 5 minutes
@app.post("/webhooks/salesbooth")
def handle_webhook():
sig = request.headers.get("X-Salesbooth-Signature", "")
timestamp = request.headers.get("X-Salesbooth-Timestamp", "0")
body = request.get_data() # raw bytes — do NOT parse before verifying
# Replay protection: reject events older than 5 minutes
if abs(time.time() - int(timestamp)) > TOLERANCE:
abort(400, "Stale webhook")
# HMAC-SHA256: sign timestamp.body
payload = f"{timestamp}.".encode() + body
expected = 'v1=' + hmac.new(WEBHOOK_SECRET.encode(), payload, hashlib.sha256).hexdigest()
# Constant-time comparison
if not hmac.compare_digest(sig, expected):
abort(400, "Invalid signature")
event = request.get_json()
print(f"Event: {event['event']} id={event['id']}")
return "", 200
curl Examples
curl — List deals with filters
curl "https://api.salesbooth.com/v1/deals?status=in_progress&limit=20" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
curl — Create a product
curl -X POST https://api.salesbooth.com/v1/products \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"name": "Enterprise License",
"price": 4999.00,
"type": "service",
"description": "Annual enterprise subscription"
}'
curl — Score a deal (Intelligence API)
curl "https://api.salesbooth.com/v1/intelligence?deal_id=deal_abc123&type=score" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
What’s Next
| Topic | Jump to |
| Receive real-time events for deal changes, payments, and renewals | Webhooks |
| Let buyers propose & counter deal terms | Negotiations |
| Build AI agents that negotiate and close deals autonomously | Agent Integration |
| Grant sub-agents constrained spending authority | Delegations |
| Embed a configurable deal widget on your site | Widgets |
| Score deals and get AI pricing suggestions | Intelligence API |
| Configure product bundles, options, and rules | CPQ / Configuration |
| Full REST reference — every endpoint, parameter, and response | Core Resources |
Security Best Practices
Salesbooth handles payments, contracts, and customer PII. This section explains the security controls built into the API and the patterns you should follow in your integration.
Idempotency Keys
Any POST request that creates a financial record (deal, payment intent, subscription) accepts an optional Idempotency-Key header. If a request fails in transit or you receive no response, resend the request with the same key. The server will return the original response without double-creating the resource.
Use idempotency keys for: POST /deals, POST /payments, POST /subscriptions, POST /contracts. Keys must be unique per request, 1–64 characters, and should be regenerated for genuinely new operations.
Example — Idempotent deal creation
curl -X POST https://api.salesbooth.com/v1/deals \
-H "Authorization: Bearer sb_live_xxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2026-03-17-acme-0042" \
-d '{ "customer_id": "cust_xxxxx", "currency": "USD" }'
# Network timeout — resend with the same key; no duplicate is created.
curl -X POST https://api.salesbooth.com/v1/deals \
-H "Authorization: Bearer sb_live_xxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2026-03-17-acme-0042" \
-d '{ "customer_id": "cust_xxxxx", "currency": "USD" }'
# Returns HTTP 200 (not 201) with the originally-created deal.
Idempotency keys expire after 24 hours. Replies are cached so all responses, including errors, are returned as-is on a replay.
Field Whitelisting (Mass-Assignment Protection)
Every write endpoint accepts only the explicitly documented fields shown in its parameter table. Undocumented or system-controlled fields sent in the request body are silently dropped — they do not produce an error, and they are never persisted. This prevents mass-assignment attacks where a client might try to set server-managed values such as status, payment_status, tenant_id, or financial totals.
System-controlled fields that cannot be set by API clients:
id, tenant_id — generated by the server
status, payment_status, contract_status — controlled by state machine transitions, not free-form writes
subtotal, total, tax_amount — calculated server-side from line items
created_at, updated_at, signed_at, closed_at — set by the server on lifecycle events
version, hash_chain — used for audit integrity; never writable
To change deal status, use the action=transition action endpoint, which enforces the state machine rules. Direct status writes are rejected.
Input Validation
All inputs are validated server-side before any database write occurs. Validation errors return 400 validation_error.invalid_fields with a details.fields map indicating which fields failed and why. Client-side validation should be considered a UX improvement only — never rely on it for security.
| Rule enforced | Example |
| Numeric ranges | deposit_pct must be 0–1; negative values or values >1 are rejected with validation_error.out_of_range |
| Required fields | Missing required fields return per-field errors in details.fields |
| String lengths | Names max 255 chars, descriptions max 10,000 chars |
| Currency codes | Must match ISO 4217 (e.g. USD, EUR, AUD) |
| Tax rates | Stored as decimal(5,4); values ≥1 are treated as a percentage and normalised (e.g. 10 → 0.1000) |
Distributed Transaction Semantics
Some Salesbooth operations touch multiple subsystems (deal, contract, payment, messaging). The platform uses a saga pattern with compensating transactions to handle partial failures:
- Atomic commitment — deal creation is a single database transaction. If any part fails, the whole operation rolls back and you receive an error response. No partial deal is created.
- Saga-based orchestration — operations that span subsystems (e.g. closing a deal triggers payment settlement, contract finalisation, and webhook delivery) use async jobs. If a downstream step fails, the system retries with exponential backoff up to 3 times. You can monitor job status via the
X-Job-ID response header on long-running operations.
- Webhook delivery guarantees — webhooks are delivered at-least-once with a 3-attempt retry. Check the dead-letter queue (
GET /webhooks/dead_letter) to find undelivered events and use POST /webhooks/replay to re-deliver them.
- Idempotency on retries — use
Idempotency-Key headers so that retrying a failed request does not create duplicate records.
Data Encryption
All customer PII (names, emails, phone numbers) is encrypted at rest using per-tenant AES-256-GCM keys. Keys are rotated on a configurable schedule (default: 90 days). API responses return decrypted values to authorised callers; raw encrypted bytes are never exposed via the API.
| Layer | Mechanism |
| In transit | TLS 1.2+ enforced on all endpoints; HTTP is redirected to HTTPS |
| At rest (PII) | AES-256-GCM, per-tenant key, stored in key vault separate from data |
| At rest (database) | Full-disk encryption on all database volumes |
| API keys | Stored as bcrypt hashes; plaintext is shown only at creation time |
| Webhook secrets | Stored encrypted; only the HMAC-SHA256 signature is verifiable |
PCI Compliance
Salesbooth is a PCI DSS Level 1 certified service provider. Card data is handled entirely by Stripe — raw card numbers never pass through Salesbooth servers. Salesbooth stores only Stripe PaymentIntent IDs and tokenised payment method references.
Your integration scope is reduced: Because card data flows directly from the buyer’s browser to Stripe’s hosted fields, your application only needs to satisfy SAQ A requirements (the simplest PCI assessment level) when using the Salesbooth widget. If you build a fully custom payment flow using the Salesbooth REST API directly, consult Stripe’s PCI guidance for your integration type.
Permission Boundaries
Different operations require different API key scopes, enforcing a principle of least privilege. A single key should be granted only the scopes it genuinely needs:
| Operation | Required scope | Notes |
| Read deals / customers | deals:read / customers:read | Read-only; safe for reporting integrations |
| Create/modify deals | deals:write | Server-side only; never expose in browser JS |
| Modify contracts or templates | contracts:write | Restrict to admin-level server keys |
| Configure payments | deals:write + Stripe connection | Requires separate Stripe OAuth; finance team only |
| Widget / browser embedding | Publishable key (sb_pub_*) | Auto-scoped to products:read, customers:write, deals:write, agent:negotiate only |
| Audit export / compliance | audit:export | Separate key; never combined with write scopes |
HTTPS and TLS
All API traffic must use HTTPS. HTTP requests are upgraded automatically via 301 redirect, but you should always use HTTPS in your integration from the start. The minimum TLS version accepted is TLS 1.2; TLS 1.3 is preferred. Certificate pinning is not required but your HTTP client should validate the certificate chain.
Deals
Create, manage, and transition deals through their lifecycle. Deals contain line items and support cryptographic signing and audit trails.
List deals with optional filters, or retrieve a single deal by ID. Returns paginated results.
| Parameter | Description |
| id | Deal ID to retrieve a specific deal (e.g. deal_xxxxxxxxxx). When provided, returns a single deal object instead of a list. |
| action | Action to perform: terms (requires id), compare-terms (requires deal_id_1 & deal_id_2), audit, verify_audit, escrow, credential, valid_transitions, signing_certificate, export |
| deal_id_1 | First deal ID for compare-terms action |
| deal_id_2 | Second deal ID for compare-terms action |
| status | Filter: draft, in_progress, pending_signature, awaiting_signatures, pending_payment, partially_accepted, closed, cancelled, expired |
| customer_id | Filter by customer ID |
| created_after | ISO 8601 date filter |
| created_before | ISO 8601 date filter |
| min_value | Filter deals with total value >= this amount (used with action=export) |
| max_value | Filter deals with total value <= this amount (used with action=export) |
| search | Search by deal title or deal ID |
| limit | Max results, 1–100 (default: 50) |
| offset | Pagination offset (default: 0). Ignored when after/before cursors are provided. |
| after | Cursor for forward pagination. Pass the next_cursor from a previous response. |
| before | Cursor for backward pagination. Pass the prev_cursor from a previous response. |
| sort | Sort field for cursor pagination: created_at (default) or updated_at |
| fields | Comma-separated list of fields to include in the response (e.g. id,status,total) |
| include | Comma-separated nested resources to include (e.g. line_items,pricing,customer) |
| exclude | Comma-separated nested resources to exclude from the response |
| format | Response format shortcut: minimal returns only id, status, and updated_at |
Retrieve a single deal with its line items and signatures.
Create a new deal.
| Field | Type | Description |
| title required | string | Deal title (max 255 chars) |
| customer_id | string | Customer identifier (omit for widget negotiations or draft deals) |
| description | string | Deal description |
| currency | string | ISO 4217 currency code (default: USD) |
| tax_rate | number | Tax rate as decimal (e.g. 0.10 for 10%). Values ≥1 are automatically divided by 100 for compatibility (e.g. 10 → 0.10); prefer the decimal form. |
| deal_type | string | one_time (default) or recurring |
| billing_cycle | string | monthly, quarterly, or annual (required when deal_type is recurring) |
| presentation_currency | string | ISO 4217 currency for display (auto-converted from currency) |
| settlement_currency | string | ISO 4217 currency for settlement |
| status | string | Initial status (default: draft) |
| notes | string | Internal notes (not visible to customers) |
| metadata | object | Arbitrary key-value metadata (max depth 3) |
| deposit_required | number | Required deposit amount from the buyer. When set, payment-intent fallback charges this amount instead of the full total. |
| template_id | string | Deal template ID to create from (pre-populates fields from template) |
| validate_only | boolean | Query param. If true, validates the request body without creating the deal. Returns {"valid": true, "message": "Validation passed"} on success (default: false). |
Example
curl -X POST https://api.salesbooth.com/v1/deals \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cust_xxxxx",
"title": "Enterprise License Deal",
"currency": "USD",
"tax_rate": 0.10
}'
Response (201)
{
"error": false,
"success": true,
"data": {
"deal": {
"deal_id": "deal_abc123",
"version": 1,
"customer_id": "cust_xxxxx",
"title": "Enterprise License Deal",
"status": "draft",
"currency": "USD",
"line_items": [],
"pricing": {
"currency": "USD",
"tax_rate": "0.1000",
"subtotal": { "amount": "0.00", "currency": "USD", "formatted": "$0.00" },
"total": { "amount": "0.00", "currency": "USD", "formatted": "$0.00" }
},
"created_at": "2026-03-09T10:30:00Z",
"updated_at": "2026-03-09T10:30:00Z"
}
}
}
Update deal fields. Send only the fields you want to change. Requires an If-Match header with the current ETag version for optimistic locking.
| Field | Type | Description |
| customer_id | string | Customer ID to reassign this deal to |
| title | string | Deal title |
| description | string | Deal description |
| notes | string | Internal notes |
| currency | string | ISO 4217 currency code (e.g. USD) |
| tax_rate | number | Tax rate as decimal (e.g. 0.10 for 10%). Values ≥1 are automatically divided by 100 for compatibility (e.g. 10 → 0.10); prefer the decimal form. |
| deposit_required | number | Required deposit amount in the deal currency. Must be ≥ 0. |
| deal_type | string | one_time or recurring |
| billing_cycle | string | monthly, quarterly, or annual |
| metadata | object | Arbitrary key-value metadata (max depth 3) |
Note: Deal status cannot be changed via PATCH. Use POST /deals?action=transition&status={new_status} instead.
Example
curl -X PATCH "https://api.salesbooth.com/v1/deals?id=deal_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-H "If-Match: 3" \
-d '{
"currency": "AUD",
"tax_rate": 0.10,
"notes": "Updated pricing agreed in call"
}'
Cancel a deal (transitions to cancelled status). If the deal is already cancelled, it is hard-deleted. Pass action=remove_item&item_id={id} to remove a single line item instead.
Example — Cancel deal
curl -X DELETE "https://api.salesbooth.com/v1/deals?id=deal_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "If-Match: 1"
Example — Remove line item
curl -X DELETE "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=remove_item&item_id=item_yyyyy" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "If-Match: 1"
Deal Actions
Add a line item to a deal.
| Field | Type | Description |
| product_id required | string | Product to add |
| name required | string | Line item display name |
| unit_price required | number | Unit price |
| quantity | integer | Quantity (default 1) |
| description | string | Line item description |
| configuration | object | Selected configuration options |
| price_type | string | Pricing model: once_off, recurring, or metered |
| billing_cycle | string | Billing frequency: monthly, quarterly, or annual |
Example
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=add_item" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"product_id": "prod_xxxxx",
"name": "Professional Plan",
"unit_price": 99.00,
"quantity": 1
}'
Return the set of status transitions currently allowed for a deal, based on its current state and any active conditions (signing requirements, escrow holds, etc.). Use this before showing state-change UI to the user.
Example
curl "https://api.salesbooth.com/v1/deals/deal_xxxxx/valid-transitions" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"deal_id": "deal_xxxxx",
"current_status": "in_progress",
"transitions": [
{
"target": "pending_signature",
"available": true,
"conditions": [],
"action": {
"method": "POST",
"endpoint": "/api/v1/deals?id=deal_xxxxx&action=transition&status=pending_signature",
"description": "Send for signature"
}
},
{
"target": "cancelled",
"available": true,
"conditions": [],
"action": {
"method": "POST",
"endpoint": "/api/v1/deals?id=deal_xxxxx&action=transition&status=cancelled",
"description": "Cancel"
}
}
]
}
}
Transition a deal to a new status. Valid target statuses: in_progress, pending_signature, awaiting_signatures, pending_payment, partially_accepted, closed, cancelled, expired. Not all transitions are valid from every state — see the state machine documentation for allowed paths.
Cryptographically sign a deal. Creates a verifiable signature with hash chain.
| Field | Type | Description |
| signer_type | string | user, customer, agent, or api_key |
| signer_id | string | ID of the signer (optional; defaults to the authenticated identity) |
| signer_customer_id | string | Customer ID to sign on behalf of. Required when an API key signs a deal that belongs to a specific customer. Triggers authorization checks via the deal's customer association. |
| consent_to_sign | boolean | Required true for human signers (user or customer) |
Example
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=sign" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"consent_to_sign": true}'
Remove the signature from a deal, reverting it to an unsigned state. Only valid while the deal has not been closed.
| Field | Type | Description |
| reason | string | Optional reason for removing the signature (recorded in audit log) |
Example
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=unsign" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"reason": "Terms need revision"}'
Update the quantity of an existing line item on a deal. The item_id query parameter is required.
| Field | Type | Description |
| quantity required | integer | New quantity (minimum: 1) |
Example
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=update_item&item_id=item_yyyyy" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"quantity": 3}'
Apply a discount to a deal. Discounts can be a fixed amount or a percentage of the deal total.
| Field | Type | Description |
| type required | string | percentage or fixed |
| value required | number | Discount value — percentage points (e.g. 10 for 10% off) or fixed currency amount |
| code | string | Optional promo code associated with this discount |
| description | string | Human-readable description of the discount (shown on invoice) |
Example — 15% off
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=apply_discount" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"type": "percentage",
"value": 15,
"description": "Loyalty discount"
}'
Example — $50 fixed discount
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=apply_discount" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"type": "fixed",
"value": 50,
"code": "SAVE50",
"description": "Promotional offer"
}'
Attach structured, machine-readable deal terms to a deal. Terms are versioned and validated against the active deal-terms schema. Once set, terms are included in the signed hash and can be verified by third parties.
| Field | Type | Description |
| terms required | object | Deal terms object. Must include terms_schema_version and payment_terms. See Deal Terms Schema for the full field reference. |
Example
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=set-terms" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"terms": {
"terms_schema_version": "1.0",
"payment_terms": {
"type": "net",
"due_date": "2026-04-30"
}
}
}'
Atomically create a fully-configured deal — customer, line items, discounts, and terms — in a single request. Designed for agent workflows and integrations that need to create ready-to-sign deals without multiple round-trips. Requires the agent:execute API key scope.
| Field | Type | Description |
| customer_id | string | Existing customer ID. Provide either customer_id or customer (inline create) |
| customer | object | Inline customer: name, email, phone, company. Creates the customer if they don't exist (matched by email) |
| items | array | Line items array. Each item: product_id, quantity, unit_price, name, optional configuration with option_ids |
| saved_config_id | string | Saved product configuration ID. Use instead of items to populate line items from a saved configuration |
| discounts | array | Optional discounts array. Each entry: type (percentage or fixed), value, code (promo code for tracking), description (human-readable label) |
| template_id | string | Optional deal template to apply default settings from |
| currency | string | ISO 4217 currency code (e.g. USD) |
| notes | string | Internal notes |
| metadata | object | Arbitrary key-value metadata |
| dry_run | boolean | If true, validates and returns the deal object without persisting it |
Example
curl -X POST "https://api.salesbooth.com/v1/deals?action=create-configured" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"customer": {
"name": "Jane Smith",
"email": "jane@example.com",
"company": "Acme Corp"
},
"items": [
{
"product_id": "prod_xxxxx",
"name": "Professional Plan",
"quantity": 1,
"unit_price": 499.00
}
],
"discounts": [
{"type": "percentage", "value": 10, "code": "first_year"}
],
"currency": "USD"
}'
Accept a subset of line items from a deal, rejecting the rest. The deal transitions to partially_accepted status. Optionally creates a separate deal for the rejected items.
| Field | Type | Description |
| accepted_items required | array | Array of line item IDs to accept (at least one required) |
| rejected_items | array | Array of line item IDs being explicitly rejected (informational) |
| create_declined_deal | boolean | If true, create a new deal containing the rejected items for further negotiation |
Example
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=partial_accept" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"accepted_items": ["item_aaa", "item_bbb"],
"rejected_items": ["item_ccc"],
"create_declined_deal": true
}'
Place deal funds in escrow, pending fulfilment of one or more conditions. Funds are held until all conditions are met (triggering release_escrow) or the escrow expires/is refunded. Escrow expires after 7 days by default.
| Field | Type | Description |
| conditions required | array | Array of condition objects, each with type (e.g. delivery, approval) and optional config |
| amount | number | Amount to hold in escrow. Defaults to the deal total |
| currency | string | ISO 4217 currency code. Defaults to the deal currency |
| expires_in | integer | Seconds until the escrow expires (default: 604800 / 7 days) |
Example
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=escrow" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"conditions": [
{"type": "delivery", "config": {"tracking_required": true}},
{"type": "approval"}
],
"expires_in": 1209600
}'
Release held escrow funds to the seller. All conditions must be fulfilled before release is permitted. Triggers the escrow.released webhook event and closes the deal.
Example
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=release_escrow" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Refund escrowed funds back to the buyer and cancel the escrow hold. Triggers the escrow.refunded webhook event.
| Field | Type | Description |
| reason | string | Reason for refund: manual (default), condition_failed, deal_cancelled, fraud, or duplicate |
Example
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=refund_escrow" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"reason": "condition_failed"}'
Mark a specific escrow condition as fulfilled. When all conditions on an escrow are fulfilled, the funds become releasable. Triggers the escrow.condition_fulfilled webhook event.
| Field | Type | Description |
| condition_id required | string | ID of the escrow condition to mark as fulfilled |
| met_by | string | Optional identifier of the party or system that fulfilled the condition |
Example
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=fulfill_condition" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"condition_id": "cond_yyyyy",
"met_by": "logistics_system"
}'
Revoke the verifiable credential issued for a signed deal. The credential is added to the revocation list and can no longer be used to verify the deal. Use when a deal is disputed, superseded, or the credential is compromised.
| Field | Type | Description |
| reason | string | Reason for revocation: manual (default), deal_cancelled, fraud, expired, or superseded |
Example
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=revoke_credential" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"reason": "superseded"}'
Record the win/loss outcome of a deal for pipeline analytics and forecasting. Can include competitor information for loss analysis. Recorded outcomes feed the deal intelligence module.
| Field | Type | Description |
| reason required | string | Outcome reason. Typically won, lost, no_decision, or a custom value |
| notes | string | Free-text notes about the outcome (stored in audit log) |
| competitor_name | string | Name of the competitor chosen instead (for loss analysis) |
Example — Won deal
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=record-outcome" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"reason": "won", "notes": "Closed after demo on 2026-03-28"}'
Example — Lost deal
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=record-outcome" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"reason": "lost",
"notes": "Went with competitor on price",
"competitor_name": "CompetitorCo"
}'
Save the current deal as a reusable deal template. The template captures the deal structure (line items, terms, discounts, metadata) and can be used to create new deals with the same configuration via template_id on a create request.
| Field | Type | Description |
| name required | string | Template name (1–255 characters) |
| description | string | Optional description shown in the template picker |
Example
curl -X POST "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=save-as-template" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"name": "Enterprise Annual Plan",
"description": "Standard enterprise deal with annual billing and 10% loyalty discount"
}'
Retrieve the immutable audit trail for a deal.
Verify the cryptographic integrity of a deal's audit chain. Checks that every audit entry links correctly to the previous one and that no entries have been inserted, removed, or altered after the fact.
Example
curl "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=verify_audit" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"status": "verified",
"total_entries": 14,
"verified_at": "2026-05-14T04:00:00Z"
}
}
Return structured deal terms as a machine-readable object. Use this to programmatically inspect pricing rules, payment schedules, delivery conditions, and other term fields without parsing free-text.
Example
curl "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=terms" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"deal_id": "deal_xxxxx",
"terms_schema_version": "1.0",
"terms": {
"payment_terms": "net_30",
"delivery_method": "digital",
"warranty_months": 12
}
}
}
Compare the structured terms between two deals side by side. Useful for reviewing revisions, counter-proposals, or template variations. Both deals must belong to the same tenant.
| Parameter | Type | Description |
| deal_id_1 required | string | First deal ID |
| deal_id_2 required | string | Second deal ID to compare against |
Example
curl "https://api.salesbooth.com/v1/deals?action=compare-terms&deal_id_1=deal_aaaaa&deal_id_2=deal_bbbbb" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Generate a structured proof document of the signing event for legal purposes. The certificate includes signer identities, signature hashes, IP addresses, timestamps, consent events, and hash-chain verification status. Suitable as an exhibit for dispute resolution or compliance audits.
Example
curl "https://api.salesbooth.com/v1/deals?id=deal_xxxxx&action=signing_certificate" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"certificate_version": "1.0",
"generated_at": "2026-05-14T04:00:00Z",
"legislation": "Electronic Transactions Act 1999 (Cth) and state/territory equivalents",
"deal": {
"deal_id": "deal_xxxxx",
"title": "Enterprise Annual Plan",
"status": "signed",
"currency": "AUD",
"total": "4500.00",
"created_at": "2026-05-10T09:00:00Z"
},
"signers": [
{
"signature_id": "sig_abc",
"signer_type": "user",
"signer_id": "user_zzz",
"signature_method": "click-to-sign",
"signature_algorithm": "ed25519",
"signature_hash": "a3f2b1c9...",
"signed_at": "2026-05-12T11:22:00Z",
"is_agent_signer": false
}
],
"consent_events": [],
"hash_chain_verification": {
"status": "verified",
"total_entries": 14,
"verified_at": "2026-05-14T04:00:00Z"
},
"note": "This certificate is produced by Salesbooth and is not legal advice."
}
}
Bulk export deals as CSV, JSON, or JSONL. Accepts all standard list filters (status, created_after, created_before, customer_id, search). Rate-limited to 10 exports per hour. The response streams directly — no JSON envelope wrapper.
| Parameter | Type | Description |
| format | string | Output format: csv (default), json, or jsonl |
| status | string | Filter by deal status (e.g. signed, draft) |
| created_after | string | ISO 8601 date — only include deals created after this date |
| created_before | string | ISO 8601 date — only include deals created before this date |
| customer_id | string | Filter to deals for a specific customer |
Example — CSV export
curl "https://api.salesbooth.com/v1/deals?action=export&format=csv&status=signed" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-o deals.csv
Example — JSONL export
curl "https://api.salesbooth.com/v1/deals?action=export&format=jsonl&created_after=2026-01-01" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-o deals.jsonl
Retrieve revenue-share settlement records for a closed deal. Returns the final breakdown of proceeds distributed to all participants (seller, buyer, platform, deal participants with revenue-share agreements).
Example
curl "https://api.salesbooth.com/v1/deals/deal_xxxxx/settlements" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"settlements": [
{
"id": "setl_abc",
"deal_id": "deal_xxxxx",
"participant_id": "part_abc",
"amount": "850.00",
"currency": "USD",
"status": "settled",
"payment_method": "stripe",
"stripe_transfer_id": "tr_abc123",
"usdc_tx_id": null,
"attempts": 1,
"error_message": null,
"settled_at": "2026-03-10T12:00:00Z",
"created_at": "2026-03-09T10:30:00Z",
"participant": {
"role": "seller",
"scope_description": null,
"revenue_share_percent": 85.00,
"agent_name": null,
"agent_key_id": null,
"is_agent": false
}
},
{
"id": "setl_def",
"deal_id": "deal_xxxxx",
"participant_id": "part_def",
"amount": "150.00",
"currency": "USD",
"status": "settled",
"payment_method": "usdc",
"stripe_transfer_id": null,
"usdc_tx_id": "0xabc123",
"attempts": 1,
"error_message": null,
"settled_at": "2026-03-10T12:00:00Z",
"created_at": "2026-03-09T10:30:00Z",
"participant": {
"role": "referrer",
"scope_description": "Referral partner",
"revenue_share_percent": 15.00,
"agent_name": "Referral Agent",
"agent_key_id": "key_agent_xxxxx",
"is_agent": true
}
}
]
}
}
Verify deal or contract integrity. Public endpoint — no authentication required. Confirms that a deal or contract has not been tampered with after signing by comparing the current state hash against the signed state hash. Third parties who receive deals can use this to independently verify authenticity.
| Parameter | Type | Description |
| id | string | Deal ID to verify (provide either id or contract_id) |
| contract_id | string | Contract ID to verify |
Example
curl "https://api.salesbooth.com/v1/deals/verify?id=deal_abc123"
Response
{
"error": false,
"data": {
"verification": {
"deal_id": "deal_abc123",
"status": "verified",
"message": "Deal signature is valid and data is unmodified",
"deal_hash": {
"stored": "a3f2b1c9...",
"current": "a3f2b1c9...",
"matches": true
},
"signature": {
"valid": true,
"signature_algorithm": "ed25519",
"signed_at": "2026-03-10T14:22:00Z"
},
"verification_method": "public_key",
"verification_note": "This signature can be independently verified using the public key without trusting Salesbooth infrastructure."
}
}
}
Possible status values: verified (deal matches signed state), tampered (deal was modified after signing), unsigned (no signature exists).
Customers
Manage customer records. Sensitive PII (name, email, phone) is encrypted at rest with searchable blind indexes.
List customers with optional filters.
| Parameter | Description |
| id | Customer ID to retrieve a specific customer (e.g. cust_xxxxxxxxxx). When provided, returns a single customer object instead of a list. |
| status | Filter: active, inactive, archived |
| search | Search name, email, phone, or company |
| limit | Max results, 1–100 (default: 50) |
| offset | Pagination offset (default: 0). Ignored when after/before cursors are provided. |
| after | Cursor for forward pagination. Pass the next_cursor from a previous response. |
| before | Cursor for backward pagination. Pass the prev_cursor from a previous response. |
| sort | Sort field for cursor pagination: created_at (default) or updated_at |
| fields | Comma-separated list of fields to include in the response (e.g. id,status,name) |
| include | Comma-separated nested resources to include (e.g. deals,contracts,activity_log) |
| exclude | Comma-separated nested resources to exclude from the response |
| format | Response format shortcut: minimal returns only id, status, and updated_at |
Retrieve a single customer with their deals and activity log.
Create a new customer.
Example
curl -X POST https://api.salesbooth.com/v1/customers \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Smith",
"email": "jane@example.com",
"phone": "+61412345678",
"company": "Acme Corp",
"status": "active"
}'
| Field | Description |
| name required | Customer full name |
| email required | Email address |
| phone | Phone number (E.164 format) |
| company | Company or organisation name |
| city | City |
| state | State or region |
| zip | Postal code |
| country | Country code (e.g. AU) |
| address | Street address |
| notes | Internal notes |
| status | Customer status: active (default), inactive, archived |
| validate_only | Query param. If true, validates the request body without creating the customer. Returns {"valid": true, "message": "Validation passed"} on success (default: false). |
Update an existing customer. Send only the fields you want to change. Requires an If-Match header with the current ETag version for optimistic locking.
| Field | Type | Description |
| name | string | Full name |
| email | string | Email address (must be unique per tenant) |
| phone | string | Phone number (normalised to E.164) |
| address | string | Street address |
| company | string | Company name |
| city | string | City |
| state | string | State or province |
| zip | string | Postal code |
| country | string | Country |
| notes | string | Internal notes |
| status | string | active, inactive, or archived |
Example
curl -X PATCH "https://api.salesbooth.com/v1/customers?id=cust_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-H "If-Match: 5" \
-d '{
"phone": "+14155552671",
"company": "Acme Corp (updated)",
"status": "active"
}'
Permanently delete a customer record and all associated data. This action cannot be undone.
Example
curl -X DELETE "https://api.salesbooth.com/v1/customers?id=cust_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "If-Match: 1"
Products
Manage your product catalogue. Products can be physical goods or services and are referenced by deal line items.
List products with optional filters.
| Parameter | Description |
| id | Product ID to retrieve a specific product (e.g. prod_xxxxxxxxxx). When provided, returns a single product object instead of a list. |
| action | Sub-action to perform: options (requires id) — returns the product’s configuration options schema |
| status | Filter: active, inactive, archived |
| type | Filter: product, service, subscription, bundle |
| category | Filter by category name |
| family | Filter by product family ID |
| requires_booking | Filter to bookable service products: 1 to include only bookable products, 0 to exclude them |
| search | Search name, SKU, or description |
| limit | Max results, 1–100 (default: 50) |
| offset | Pagination offset (default: 0). Ignored when after/before cursors are provided. |
| after | Cursor for forward pagination. Pass the next_cursor from a previous response. |
| before | Cursor for backward pagination. Pass the prev_cursor from a previous response. |
| sort | Sort field for cursor pagination: created_at (default) or updated_at |
| fields | Comma-separated list of fields to include in the response (e.g. id,status,name,price) |
| include | Comma-separated nested resources to include (e.g. deals,activity_log) |
| exclude | Comma-separated nested resources to exclude from the response |
| format | Response format shortcut: minimal returns only id, status, and updated_at |
Create a new product.
Example
curl -X POST https://api.salesbooth.com/v1/products \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"name": "Enterprise License",
"price": 999.00,
"type": "service",
"description": "Annual enterprise license",
"sku": "ENT-001"
}'
| Field | Type | Description |
| name required | string | Product name |
| price required | number | Selling price |
| description | string | Product description |
| sku | string | Stock keeping unit |
| type | string | product, service, subscription, or bundle |
| price_type | string | once_off, recurring, percentage, or metered |
| billing_cycle | string | monthly, quarterly, or annual — required when price_type is recurring |
| pricing_model | string | fixed, tiered, volume, or usage |
| cost | number | Cost price (for margin calculation) |
| unit | string | Unit label (e.g. “per seat”, “per month”) |
| tax_rate | number | Tax rate as decimal (e.g. 0.10 for 10%) |
| category | string | Product category |
| status | string | active, inactive, or archived (default: active) |
| stock_quantity | integer | Available stock quantity |
| track_inventory | boolean | Enable inventory tracking for this product |
| low_stock_threshold | integer | Stock level at which low-stock alerts are triggered |
| metadata | object | Arbitrary key-value metadata |
| configuration_schema | object | JSON schema defining configurable options for this product |
| family_id | string | Product family ID to associate this product with |
| requires_booking | boolean | Whether this product requires a booking (default: false) |
| session_duration | integer | Session length in minutes (5–480) |
| buffer_time | integer | Buffer time between sessions in minutes (0–120) |
| max_advance_days | integer | Maximum days in advance a booking can be made (default: 90) |
| min_advance_hours | integer | Minimum hours lead time required for a booking (default: 24) |
| allow_staff_selection | boolean | Whether customers can choose their preferred staff member (default: true) |
| learn_more_url | string | URL linking to more information about the product |
| features | array | List of product feature strings |
| validate_only | boolean | Query param. If true, validates the request body without creating the product. Returns {"valid": true, "message": "Validation passed"} on success (default: false). |
Update an existing product. Send only the fields you want to change. Requires an If-Match header with the current ETag version for optimistic locking.
| Field | Type | Description |
| name | string | Product name |
| description | string | Product description |
| price | number | Unit price |
| cost | number | Cost price (for margin calculation) |
| sku | string | Stock keeping unit |
| type | string | product, service, subscription, or bundle |
| unit | string | Unit label (e.g. “per seat”) |
| tax_rate | number | Tax rate as decimal (e.g. 0.10 for 10%) |
| category | string | Product category |
| status | string | active, inactive, or archived |
| stock_quantity | integer | Available stock quantity |
| track_inventory | boolean | Enable inventory tracking |
| low_stock_threshold | integer | Stock level at which low-stock alerts are triggered |
| price_type | string | once_off, recurring, percentage, or metered |
| billing_cycle | string | monthly, quarterly, or annual — required when price_type is recurring |
| pricing_model | string | fixed, tiered, volume, or usage |
| metadata | object | Arbitrary key-value metadata |
| configuration_schema | object | JSON schema defining configurable options for this product |
| family_id | string | Product family ID to associate this product with |
| requires_booking | boolean | Whether this product requires a booking |
| session_duration | integer | Session length in minutes (5–480) |
| buffer_time | integer | Buffer time between sessions in minutes (0–120) |
| max_advance_days | integer | Maximum days in advance a booking can be made |
| min_advance_hours | integer | Minimum hours lead time required for a booking |
| allow_staff_selection | boolean | Whether customers can choose their preferred staff member |
| learn_more_url | string | URL linking to more information about the product |
| features | array | List of product feature strings |
Example
curl -X PATCH "https://api.salesbooth.com/v1/products?id=prod_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-H "If-Match: 2" \
-d '{
"price": 1199.00,
"status": "active",
"stock_quantity": 50
}'
Permanently delete a product. Products referenced by existing deal line items cannot be deleted while those deals are active.
Example
curl -X DELETE "https://api.salesbooth.com/v1/products?id=prod_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "If-Match: 1"
Contracts
Create and manage contracts with lifecycle transitions, cryptographic signing, and immutable audit trails.
List contracts with optional filters.
| Parameter | Description |
| id | Contract ID to retrieve a specific contract. When provided, returns a single contract object instead of a list. |
| action | Action to perform (requires id): audit, verify_audit, signing_certificate |
| status | Filter: draft, pending, signed, active, expired, terminated |
| customer_id | Filter by customer |
| renewal_type | Filter by renewal type: manual, auto, none |
| expiring_soon | Filter contracts expiring within N days (e.g. 30 for contracts expiring in the next 30 days) |
| limit | Max results, 1–100 (default: 50) |
| offset | Pagination offset (default: 0). Ignored when after/before cursors are provided. |
| after | Cursor for forward pagination. Pass the next_cursor from a previous response. |
| before | Cursor for backward pagination. Pass the prev_cursor from a previous response. |
| sort | Sort field for cursor pagination: created_at (default) or updated_at |
| fields | Comma-separated list of fields to include in the response (e.g. contract_id,status,title,value) |
| include | Comma-separated nested resources to include (e.g. activity_log) |
| exclude | Comma-separated nested resources to exclude from the response |
| format | Response format shortcut: minimal returns only contract_id, status, and updated_at |
Create a new contract. You can create a contract directly, or from an existing deal using deal_id (which auto-populates customer, value, dates, and currency).
Example — create from a deal
curl -X POST https://api.salesbooth.com/v1/contracts \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"deal_id": "deal_xxxxx",
"payment_terms": "net30",
"renewal_type": "auto"
}'
Example — create directly
curl -X POST https://api.salesbooth.com/v1/contracts \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cust_xxxxx",
"title": "Annual Support Agreement",
"value": 12000.00,
"currency": "AUD",
"start_date": "2026-04-01",
"end_date": "2027-03-31",
"payment_terms": "net30",
"renewal_type": "auto"
}'
| Field | Description |
| deal_id | Create a contract from an existing deal. Auto-populates customer_id, title, value, currency, start_date, and end_date from the deal. Any of those fields may still be provided to override the deal-derived values. Required unless the five core fields are supplied. |
| customer_id required* | Customer to attach the contract to. Required unless deal_id is provided. |
| title required* | Contract title. Required unless deal_id is provided. |
| value required* | Contract value (numeric, ≥ 0). Required unless deal_id is provided. |
| start_date required* | Contract start date (YYYY-MM-DD). Required unless deal_id is provided. |
| end_date required* | Contract end date (YYYY-MM-DD, must be after start_date). Required unless deal_id is provided. |
| contract_number | Custom contract reference number (e.g. CTR-2026-001). |
| description | Contract description. |
| currency | ISO 4217 currency code (default: USD). |
| payment_terms | Payment terms text (e.g. net30). |
| renewal_type | Renewal configuration: auto, manual, or none (default: manual). |
| renewal_terms | Structured renewal terms object (JSON). Stores renewal period, notice window, and other renewal-specific configuration. |
| notes | Internal notes (not visible to the customer). |
| validate_only | Query param. If true, validates the request body without creating the contract. Returns {"valid": true, "message": "Validation passed"} on success (default: false). |
* Required unless deal_id is provided.
Update fields on an existing contract. Requires an If-Match header with the current ETag for optimistic locking.
| Field | Description |
| title | Contract title |
| description | Contract description. |
| value | Contract value (numeric, ≥ 0) |
| currency | ISO 4217 currency code |
| start_date | Contract start date (YYYY-MM-DD) |
| end_date | Contract end date (YYYY-MM-DD, must be after start_date) |
| renewal_type | Renewal configuration: auto, manual, or none |
| renewal_terms | Structured renewal terms object (JSON). Stores renewal period, notice window, and other renewal-specific configuration. |
| payment_terms | Payment terms text (e.g. net30) |
| notes | Internal notes (not visible to the customer). |
| status | Contract status: draft, pending, signed, active, expired, terminated |
| customer_id | Reassign the contract to a different customer. |
| contract_number | Custom contract reference number (e.g. CTR-2026-001). |
Example
curl -X PATCH "https://api.salesbooth.com/v1/contracts?id=42" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-H "If-Match: 1" \
-d '{
"title": "Annual SaaS Agreement (Revised)",
"payment_terms": "net30",
"end_date": "2027-01-31"
}'
Delete a contract. Active contracts must be terminated first (use the terminate action). Requires an If-Match header with the current ETag.
Example
curl -X DELETE "https://api.salesbooth.com/v1/contracts?id=42" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "If-Match: 2"
Contract Actions
Sign a draft contract. Creates a cryptographic signature.
Activate a signed contract.
Terminate an active contract.
Manually trigger contract renewal. Creates a new contract period based on the original terms.
Opt out of an upcoming auto-renewal. The contract will expire at the end of its current term instead of renewing.
Payments
Manage the payment lifecycle for deals via Stripe PaymentIntents. Create payment intents, confirm payments, issue refunds, and record manual payments.
Get payment status for a deal, including Stripe PaymentIntent details and payment history.
| Parameter | Type | Description |
| deal_id required | string | The deal identifier |
Example
curl https://api.salesbooth.com/v1/payments?deal_id=deal_abc123 \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Retrieve payment provider settings and Stripe connection status.
Example
curl https://api.salesbooth.com/v1/payments?action=settings \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Deprecated — use
POST /api/v1/payment-intent instead. Create a Stripe PaymentIntent for a deal. Returns a client secret for frontend payment confirmation.
| Field | Type | Description |
| deal_id required | string | The deal to collect payment for |
| amount | number | Amount in major currency units (defaults to deal total) |
| currency | string | ISO 4217 currency code (defaults to deal currency) |
Example
curl -X POST https://api.salesbooth.com/v1/payments?action=create-intent \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"deal_id": "deal_abc123",
"amount": 1099.00,
"currency": "USD"
}'
Response (200)
{
"error": false,
"data": {
"payment_intent_id": "pi_xxxxx",
"client_secret": "pi_xxxxx_secret_xxxxx",
"amount": 1099.00,
"currency": "usd"
}
}
Confirm a payment intent after the customer has provided a payment method.
| Field | Type | Description |
| deal_id required | string | The deal to confirm payment for |
| payment_intent_id required | string | The Stripe PaymentIntent ID |
Example
curl -X POST https://api.salesbooth.com/v1/payments?action=confirm \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "deal_id": "deal_xxxxx", "payment_intent_id": "pi_xxxxx" }'
Issue a full or partial refund on a completed payment.
| Field | Type | Description |
| deal_id required | string | The deal to refund |
| amount | number | Partial refund amount (omit for full refund) |
| reason | string | Refund reason |
Example
curl -X POST https://api.salesbooth.com/v1/payments?action=refund \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"deal_id": "deal_abc123",
"amount": 200.00,
"reason": "Partial refund for returned item"
}'
Record a manual (offline) payment for a deal — bank transfer, cheque, or cash.
| Field | Type | Description |
| deal_id required | string | The deal identifier |
| amount required | number | Payment amount (minimum 0.01) |
| method required | string | Payment method: cash, wire, cheque, bank_transfer, or other |
| reference | string | Reference number or identifier for the payment |
| notes | string | Additional notes about the payment |
Example
curl -X POST https://api.salesbooth.com/v1/payments?action=record-manual \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "deal_id": "deal_abc123", "amount": 5000.00, "method": "bank_transfer", "reference": "TXN-001" }'
Capture a previously-authorized PaymentIntent that is in requires_capture state.
| Field | Type | Description |
| deal_id required | string | The deal the payment belongs to |
| payment_intent_id required | string | The Stripe PaymentIntent ID to capture |
| amount_to_capture | number | Amount to capture in currency units. Defaults to the full authorized amount. |
Example
curl -X POST https://api.salesbooth.com/v1/payments?action=capture \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"deal_id": "deal_abc123",
"payment_intent_id": "pi_xxxxx"
}'
Response (200)
{
"error": false,
"data": {
"payment_intent_id": "pi_xxxxx",
"captured_amount": 1099.00,
"currency": "usd",
"payment_status": "succeeded",
"deal_status": "closed"
}
}
Charge a customer's saved payment method off-session. Intended for agent-driven payment collection.
| Field | Type | Description |
| deal_id required | string | The deal to charge payment for |
| customer_id required | string | The customer whose saved payment method to charge |
| payment_method_id | string | Specific Stripe payment method ID. Defaults to the customer's default payment method. |
Example
curl -X POST https://api.salesbooth.com/v1/payments?action=charge-saved-method \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"deal_id": "deal_abc123",
"customer_id": "cust_xyz789"
}'
Response (200)
{
"error": false,
"data": {
"payment_intent_id": "pi_xxxxx",
"amount": 1099.00,
"currency": "usd",
"payment_status": "succeeded",
"deal_status": "closed",
"balance_due": 0.00
}
}
Poll the current status of a Stripe PaymentIntent. Useful for agents that need to check payment state without relying on webhooks.
| Field | Type | Description |
| payment_intent_id required | string | The Stripe PaymentIntent ID to poll |
Example
curl -X POST https://api.salesbooth.com/v1/payments?action=poll-intent \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "payment_intent_id": "pi_xxxxx" }'
Response (200)
{
"error": false,
"data": {
"payment_intent_id": "pi_xxxxx",
"status": "succeeded",
"amount": 1099.00,
"amount_received": 1099.00,
"currency": "usd",
"last_payment_error": null
}
}
Generate a Stripe Checkout Session URL so a customer can complete payment via a hosted page. Intended for agent-driven payment link delivery.
| Field | Type | Description |
| deal_id required | string | The deal to generate a payment link for |
| success_url | string | URL to redirect the customer to after successful payment |
| cancel_url | string | URL to redirect the customer to if they cancel |
Example
curl -X POST https://api.salesbooth.com/v1/payments?action=generate-link \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "deal_id": "deal_abc123" }'
Response (200)
{
"error": false,
"data": {
"payment_link": "https://checkout.stripe.com/pay/cs_xxxxx",
"checkout_session_id": "cs_xxxxx",
"amount": 1099.00,
"currency": "usd",
"expires_at": "2026-05-12T01:00:00Z"
}
}
Save payment method toggles and invoice settings for the tenant.
| Field | Type | Description |
| payment_methods | object | Payment method enable/disable toggles keyed by method name (e.g. {"card": true, "bank_transfer": false}) |
| invoice_settings | object | Invoice generation and delivery settings |
Example
curl -X POST https://api.salesbooth.com/v1/payments?action=save-settings \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"payment_methods": { "card": true, "bank_transfer": false },
"invoice_settings": { "auto_send": true }
}'
Response (200)
{
"error": false,
"data": { "message": "Payment settings saved" }
}
Initiate Stripe Connect onboarding for the tenant. Returns an Account Link URL that you should redirect the user to.
Example
curl -X POST https://api.salesbooth.com/v1/payments?action=connect-stripe \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{}'
Response (200)
{
"error": false,
"data": {
"url": "https://connect.stripe.com/setup/e/acct_xxxxx/xxxxx",
"account_id": "acct_xxxxx"
}
}
Disconnect the tenant's Stripe account from Salesbooth. Disables Stripe-based payment processing until reconnected.
Example
curl -X POST https://api.salesbooth.com/v1/payments?action=disconnect-stripe \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{}'
Response (200)
{
"error": false,
"data": { "message": "Stripe account disconnected" }
}
Subscriptions
Create and manage recurring subscriptions built on top of deals. Supports billing cycles, cancellation, pausing, resuming, cycle changes, metered billing, and renewal tracking.
Subscription Lifecycle
┌───────────────────────────────────────────────────────────────────────────┐
│ SUBSCRIPTION STATE MACHINE │
│ │
│ (closed deal) │
│ │ │
│ │ action=create │
│ ▼ │
│ ┌─────────┐ action=pause ┌────────┐ action=cancel ┌───────────┐ │
│ │ active │────────────────▶│ paused │─────────────────▶│ cancelled │ │
│ └─────────┘ └────────┘ └───────────┘ │
│ │ ▲ │ │
│ │ │ action=resume │ action=resume │
│ │ └───────────────────────┘ │
│ │ │
│ │ payment fails at renewal │
│ ▼ │
│ ┌──────────┐ action=retry-payment ┌──────────┐ │
│ │ past_due │───────────────────────▶│ active │ │
│ └──────────┘ (if payment succeeds) └──────────┘ │
│ │ │
│ │ grace period expires │
│ ▼ │
│ ┌───────────┐ │
│ │ suspended │ │
│ └───────────┘ │
└───────────────────────────────────────────────────────────────────────────┘
| Status | Description |
active | Subscription is renewing normally. Metered usage is accumulating for the current cycle. |
paused | No renewals will occur. Usage meters stopped. Resume restarts from pause date. |
past_due | Most recent renewal payment failed. Subscription continues in grace period; retry payment to return to active. |
suspended | Grace period expired without successful payment. Service should be suspended. Requires manual payment recovery. |
cancelled | Subscription permanently cancelled. end_of_period: true cancels at cycle end; false cancels immediately. |
List all subscriptions or retrieve a specific one. Pass action=analytics for subscription metrics.
| Parameter | Type | Description |
| id | string | Retrieve a specific subscription by deal ID |
| status | string | Filter: active, paused, cancelled, past_due, suspended |
| action | string | analytics for subscription metrics; usage_summary (with id) for current cycle metered usage; usage_history (with id) for historical usage records; meters (with id) to list active meters |
Example — list active subscriptions
curl "https://api.salesbooth.com/v1/subscriptions?status=active" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Example — get metered usage for a subscription
curl "https://api.salesbooth.com/v1/subscriptions?id=deal_abc123&action=usage_summary" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Create a recurring subscription from a closed deal.
| Field | Type | Description |
| deal_id required | string | The deal to subscribe |
| action required | string | Query parameter — must be create |
| billing_cycle required | string | monthly, quarterly, or annual |
Example
curl -X POST "https://api.salesbooth.com/v1/subscriptions?action=create" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"deal_id": "deal_abc123",
"billing_cycle": "monthly"
}'
Pause an active subscription. No renewal charges will occur while paused.
Example
curl -X POST "https://api.salesbooth.com/v1/subscriptions?action=pause" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "deal_id": "deal_abc123" }'
Resume a paused subscription. The next renewal is recalculated from the resume date.
Example
curl -X POST "https://api.salesbooth.com/v1/subscriptions?action=resume" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "deal_id": "deal_abc123" }'
Cancel a subscription. By default cancels immediately; pass end_of_period: true to cancel at the end of the current billing period.
| Field | Type | Description |
| deal_id required | string | Subscription deal ID |
| action required | string | Query parameter — must be cancel |
| end_of_period | boolean | If true, cancels at end of the billing period. Defaults to false (immediate cancellation). |
| reason | string | Optional cancellation reason for record-keeping |
| prorate | boolean | Whether to calculate a proration credit for unused time (default: true) |
Example — cancel at period end
curl -X POST "https://api.salesbooth.com/v1/subscriptions?action=cancel" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "deal_id": "deal_abc123", "end_of_period": true }'
Manually trigger a renewal cycle for a subscription. Creates a new renewal deal and processes payment if a payment method is on file. Normally handled automatically by the cron job.
Example
curl -X POST "https://api.salesbooth.com/v1/subscriptions?action=renew" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "deal_id": "deal_abc123" }'
Retry a failed renewal payment for a past_due subscription. Optionally extends the grace period.
| Field | Type | Description |
| deal_id required | string | Subscription deal ID |
| action required | string | Query parameter — must be retry-payment |
| grace_days | integer | Additional days to extend the grace period (optional) |
Example
curl -X POST "https://api.salesbooth.com/v1/subscriptions?action=retry-payment" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "deal_id": "deal_abc123", "grace_days": 3 }'
Upgrade or downgrade a subscription by replacing its line items. Proration is applied at the next renewal cycle.
| Field | Type | Description |
| deal_id required | string | Subscription deal ID |
| action required | string | Query parameter — must be change |
| line_items required | array | New line items: product_id, quantity, unit_price |
Example — upgrade to enterprise plan
curl -X POST "https://api.salesbooth.com/v1/subscriptions?action=change" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"deal_id": "deal_abc123",
"line_items": [
{ "product_id": "prod_enterprise", "quantity": 1, "unit_price": 299.00 }
]
}'
Get a summary of metered usage for the current billing cycle across all meters on the subscription.
Example
curl "https://api.salesbooth.com/v1/subscriptions?id=deal_abc123&action=usage_summary" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"subscription_deal_id": "deal_abc123",
"billing_cycle": {
"start": "2026-03-01T00:00:00Z",
"end": "2026-04-01T00:00:00Z"
},
"meters": [
{
"meter_id": "meter_xyz789",
"metric_name": "api_calls",
"billing_model": "per_unit",
"total_quantity": 12547,
"included_quantity": 10000,
"billable_quantity": 2547,
"unit_price": 0.001,
"tiers": null,
"charge": 2.55,
"currency": "USD",
"event_count": 312
}
],
"base_amount": 99.00,
"total_usage_charges": 2.55,
"projected_total": 101.55,
"currency": "USD"
}
}
Change the billing cycle for an active subscription. Takes effect at the next renewal.
| Field | Type | Description |
| deal_id required | string | Subscription deal ID |
| action required | string | Query parameter — must be change-cycle |
| billing_cycle required | string | monthly, quarterly, or annual |
Example — upgrade to annual
curl -X POST "https://api.salesbooth.com/v1/subscriptions?action=change-cycle" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "deal_id": "deal_abc123", "billing_cycle": "annual" }'
Metered Billing
Attach usage meters to subscriptions to bill based on consumption (e.g. API calls, seats, storage). Meters accumulate usage and are billed at renewal.
Add a usage meter to a subscription. Define the metric, unit, and price per unit.
| Field | Type | Description |
| deal_id required | string | Subscription deal ID |
| action required | string | add-meter |
| metric_name required | string | Metric identifier (e.g. api_calls, seats, storage_gb) |
| billing_model | string | Billing model: per_unit, tiered, or volume (default: per_unit) |
| unit_price required | number | Price charged per unit of usage |
| included_quantity | integer | Included free units per billing period (default: 0) |
| tiers | array | Pricing tiers for tiered or volume billing models |
| currency | string | Currency code (e.g. USD); defaults to the subscription currency |
Example — add API call meter
curl -X POST https://api.salesbooth.com/v1/subscriptions \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"deal_id": "deal_abc123",
"action": "add-meter",
"metric_name": "api_calls",
"billing_model": "per_unit",
"unit_price": 0.001,
"included_quantity": 10000,
"currency": "USD"
}'
Remove a usage meter from a subscription. Accumulated usage for the current billing period is discarded.
| Field | Type | Description |
| deal_id | string | Subscription deal ID (not required; meter is identified by meter_id) |
| action required | string | remove-meter |
| meter_id required | string | ID of the meter to remove |
Example — remove API call meter
curl -X POST https://api.salesbooth.com/v1/subscriptions \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"action": "remove-meter",
"meter_id": "meter_xyz789"
}'
Record metered usage for a subscription. Call this from your application whenever a billable event occurs.
| Field | Type | Description |
| deal_id required | string | Subscription deal ID |
| action required | string | record-usage |
| metric_name required | string | Metric to record against (must exist on the subscription) |
| quantity required | number | Units consumed in this event |
| idempotency_key | string | Optional idempotency key to prevent duplicate recording |
| metadata | object | Optional key-value metadata attached to this usage event |
| records | array | Batch recording: array of usage objects (each with metric_name, quantity, and optional idempotency_key/metadata) |
Example — record 150 API calls
curl -X POST https://api.salesbooth.com/v1/subscriptions \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"deal_id": "deal_abc123",
"action": "record-usage",
"metric_name": "api_calls",
"quantity": 150,
"idempotency_key": "usage-2026-03-12-batch-7",
"metadata": { "source": "api-gateway" }
}'
Webhook events
subscription.meter_added — meter attached to subscription
subscription.renewed — renewal processed, metered charges included
subscription.past_due — payment failed at renewal
Staff
Manage staff members — service providers who can be assigned to bookable products and scheduled for availability.
Required Scopes
| staff:read | Required for listing and retrieving staff members |
| staff:write | Required for creating, updating, deactivating staff, and managing schedules |
List all active staff members, or retrieve a single staff member with their weekly schedule and assigned products.
| Parameter | Type | Description |
| id | string | Retrieve a specific staff member with schedule and assigned products |
| status | string | Filter by status: active, inactive |
| product_id | string | Filter by assigned product |
| limit | integer | Max results to return (default: 50) |
| offset | integer | Pagination offset |
Example
curl https://api.salesbooth.com/v1/staff \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Create a new staff member.
| Field | Type | Description |
| display_name required | string | Full display name of the staff member |
| title | string | Job title or role (e.g. Senior Consultant) |
| bio | string | Short biography shown to customers |
| avatar_url | string | URL of the staff member’s profile photo |
| user_id | string | Linked tenant user account ID |
| status | string | Account status: active or inactive |
| max_daily_sessions | integer | Maximum bookings per day (1–100) |
| default_session_duration | integer | Default booking duration in minutes (5–480) |
| buffer_time | integer | Buffer between bookings in minutes (0–240) |
| timezone | string | Staff member’s timezone (e.g. America/New_York) |
| metadata | object | Arbitrary key/value metadata |
| schedule | array | Weekly availability schedule (up to 7 entries) |
| product_ids | array | Product IDs this staff member is qualified to deliver |
Example
curl -X POST https://api.salesbooth.com/v1/staff \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"display_name": "Jane Smith",
"title": "Senior Consultant",
"timezone": "America/New_York"
}'
Update a staff member’s profile.
Example
curl -X PATCH "https://api.salesbooth.com/v1/staff?id=stf_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "title": "Lead Consultant" }'
Deactivate a staff member. Deactivated staff are no longer available for new bookings but existing bookings are preserved.
Example
curl -X DELETE "https://api.salesbooth.com/v1/staff?id=stf_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Schedule Management
Set the weekly availability schedule for a staff member.
| Field | Type | Description |
| schedule required | array | Array of daily schedule objects with day_of_week (0–6), start_time, end_time |
Example
curl -X POST "https://api.salesbooth.com/v1/staff?id=stf_xxxxx&action=schedule" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"schedule": [
{ "day_of_week": 1, "start_time": "09:00", "end_time": "17:00" },
{ "day_of_week": 2, "start_time": "09:00", "end_time": "17:00" }
]
}'
Add a date-specific availability override for a staff member. Use this to mark a day off (is_available: false) or set custom hours for a specific date.
| Field | Type | Description |
| override_date required | string | Date to override in YYYY-MM-DD format |
| is_available | boolean | Whether the staff member is available on this date (default: false) |
| start_time | string | Availability start time in HH:MM format — required when is_available is true |
| end_time | string | Availability end time in HH:MM format — required when is_available is true |
| reason | string | Optional note describing the reason for the override (e.g. public holiday, conference) |
Example — mark a day off
curl -X POST "https://api.salesbooth.com/v1/staff?id=stf_xxxxx&action=override" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"override_date": "2026-12-25",
"is_available": false,
"reason": "Public holiday"
}'
Example — set custom hours
curl -X POST "https://api.salesbooth.com/v1/staff?id=stf_xxxxx&action=override" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"override_date": "2026-12-31",
"is_available": true,
"start_time": "09:00",
"end_time": "13:00",
"reason": "Half day"
}'
Update an existing schedule override. Only the fields you supply are changed; omitted fields retain their current values.
| Parameter / Field | Type | Description |
| override_id required | integer | ID of the override to update (query string or request body) |
| is_available | boolean | Updated availability flag |
| start_time | string | Updated start time in HH:MM format |
| end_time | string | Updated end time in HH:MM format |
| reason | string | Updated reason note |
Example
curl -X PATCH "https://api.salesbooth.com/v1/staff?id=stf_xxxxx&action=override&override_id=42" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"start_time": "10:00",
"end_time": "14:00"
}'
Remove a date-specific schedule override, restoring the staff member’s regular weekly availability for that date.
| Parameter | Type | Description |
| override_id required | integer | ID of the override to remove |
Example
curl -X DELETE "https://api.salesbooth.com/v1/staff?id=stf_xxxxx&action=override&override_id=42" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Assign a staff member to a bookable product so they appear as available during checkout.
| Field | Type | Description |
| product_id required | string | The product to assign the staff member to |
Example
curl -X POST "https://api.salesbooth.com/v1/staff?id=stf_xxxxx&action=assign_product" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "product_id": "prod_xxxxx" }'
Bookings
Manage service bookings — hold time slots, confirm appointments, track attendance, and handle cancellations.
Required Scopes
| bookings:read | Required for listing and retrieving bookings |
| bookings:write | Required for creating, updating, and cancelling bookings |
List bookings with optional filters, or retrieve a single booking by ID.
| Parameter | Type | Description |
| id | string | Retrieve a specific booking |
| status | string | Filter: held, confirmed, completed, cancelled, no_show |
| product_id | string | Filter by product |
| staff_id | string | Filter by staff member |
| deal_id | string | Filter by associated deal |
| date_from | string (date) | Start date filter (YYYY-MM-DD) |
| date_to | string (date) | End date filter (YYYY-MM-DD) |
| action | string | analytics for booking metrics |
| period | string | Analytics period (e.g. 7d, 30d, 90d; default: 30d). Used with action=analytics |
| limit | integer | Max results (default: 50) |
| offset | integer | Pagination offset |
Example
curl https://api.salesbooth.com/v1/bookings?status=confirmed \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Create or hold a booking slot for a customer. Use status held to temporarily reserve a slot during checkout.
| Field | Type | Description |
| product_id required | string | The bookable product |
| staff_id required | string | Staff member to assign the booking to |
| date required | string (date) | Appointment date (YYYY-MM-DD) |
| start_time required | string (time) | Appointment start time (HH:MM) |
| duration | integer | Duration in minutes (default: 60) |
| customer_name | string | Customer display name |
| customer_email | string | Customer email for confirmation |
| customer_phone | string | Customer phone number |
| notes | string | Booking notes |
Example
curl -X POST https://api.salesbooth.com/v1/bookings \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"product_id": "prod_xxxxx",
"staff_id": "stf_xxxxx",
"date": "2026-03-20",
"start_time": "10:00",
"customer_name": "Alice Johnson",
"customer_email": "alice@example.com"
}'
Response (201)
{
"error": false,
"data": {
"booking": {
"booking_id": "bkng_xxxxx",
"tenant_id": "tenant_xxxxx",
"deal_id": null,
"line_item_id": null,
"product_id": "prod_xxxxx",
"product_name": "60-min Consultation",
"staff_id": "stf_xxxxx",
"staff_name": "Jane Smith",
"customer_id": null,
"customer_name": null,
"customer_email": null,
"customer_phone": null,
"booking_date": "2026-03-20",
"start_time": "10:00",
"end_time": "11:00",
"status": "held",
"hold_expires_at": "2026-03-20T10:10:00Z",
"notes": null,
"created_at": "2026-03-20T09:55:00Z",
"updated_at": "2026-03-20T09:55:00Z"
}
}
}
Transition a booking through its lifecycle. Send an action field with action-specific parameters.
| Field | Type | Description |
| action required | string | confirm, cancel, complete, no_show, or reschedule |
action: confirm
| Field | Type | Description |
| deal_id required | string | Deal to associate with this booking confirmation |
| line_item_id | string | Specific line item within the deal |
| customer_id | string | Customer to associate with this booking |
action: cancel
| Field | Type | Description |
| reason | string | Cancellation reason |
action: complete / no_show
No additional fields required.
action: reschedule
| Field | Type | Description |
| product_id required | string | Bookable product for the new slot |
| staff_id required | string | Staff member for the new slot |
| date required | string | New date in YYYY-MM-DD format |
| start_time required | string | New start time in HH:MM format |
| duration | integer | Duration in minutes (5–480, default: 60) |
| customer_name | string | Customer display name |
| customer_email | string | Customer email address |
| customer_phone | string | Customer phone number |
| notes | string | Booking notes |
Example — confirm a booking
curl -X PATCH "https://api.salesbooth.com/v1/bookings?id=bkng_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "action": "confirm", "deal_id": "deal_xxxxx" }'
Example — reschedule a booking
curl -X PATCH "https://api.salesbooth.com/v1/bookings?id=bkng_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"action": "reschedule",
"product_id": "prod_xxxxx",
"staff_id": "stf_xxxxx",
"date": "2026-04-10",
"start_time": "14:00"
}'
Cancel a booking. Releases the held time slot.
Example
curl -X DELETE "https://api.salesbooth.com/v1/bookings?id=bkng_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Availability
Check available booking slots for a bookable product. Used by the widget during checkout to present a date picker with real-time slot availability. Authenticated with a publishable key (sb_pub_*) or a secret key with products:read scope.
Return available time slots for a product on a specific date, or return a list of available dates for an entire month.
| Parameter | Type | Description |
| product_id required | string | Bookable product to check |
| date | string | Date in YYYY-MM-DD format — returns available time slots for that day |
| month | string | Month in YYYY-MM format — returns all dates with availability in the month |
| staff_id | string | Optional — filter slots for a specific staff member |
Check a specific date
curl "https://api.salesbooth.com/v1/availability?product_id=prod_xxxxx&date=2026-03-20" \
-H "Authorization: Bearer sb_pub_xxxxx"
Response (date)
{
"error": false,
"success": true,
"data": {
"slots": [
{ "start_time": "09:00:00", "end_time": "10:00:00", "staff_id": "stf_abc123", "staff_name": "Alice", "duration": 60 },
{ "start_time": "10:30:00", "end_time": "11:30:00", "staff_id": "stf_abc123", "staff_name": "Alice", "duration": 60 },
{ "start_time": "14:00:00", "end_time": "15:00:00", "staff_id": "stf_def456", "staff_name": "Bob", "duration": 60 }
],
"date": "2026-03-20",
"product_id": "prod_xxxxx"
}
}
Check a full month
curl "https://api.salesbooth.com/v1/availability?product_id=prod_xxxxx&month=2026-03" \
-H "Authorization: Bearer sb_pub_xxxxx"
Response (month)
{
"error": false,
"success": true,
"data": {
"dates": ["2026-03-18", "2026-03-19", "2026-03-20", "2026-03-25"],
"month": "2026-03",
"product_id": "prod_xxxxx"
}
}
Negotiations
Agent-to-agent and human-to-agent deal negotiation protocol. Propose terms, counter-propose, accept, or reject — all tracked with full history and optional AI suggestions. Requires agent:negotiate scope for write operations.
Who needs this: Use Negotiations if you want buyers, agents, or both parties to propose and counter-propose deal terms (discount, payment terms, delivery dates) before a deal is finalised. It is also the foundation for AI-automated bargaining between software agents.
When to skip this: For fixed-price deals where no back-and-forth is needed, you can ignore this section entirely. Create the deal, add line items, and transition directly to in_progress.
Prerequisite: An API key with agent:negotiate scope.
Negotiation Lifecycle
┌─────────────────────────────────────────────────────────────────────┐
│ NEGOTIATION STATE MACHINE │
│ │
│ ┌──────────┐ │
│ propose │ │ counter │
│ ┌───────────▶│ proposed │─────────────┐ │
│ │ │ │ │ │
│ │ └──────────┘ ▼ │
│ (no prior │ │ │ ┌──────────────┐ │
│ history) │ accept reject │ counter_ │ │
│ │ │ │ │ proposed │ │
│ │ ▼ ▼ └──────────────┘ │
│ │ ┌──────────────┐ │ │ │
│ │ │ accepted / │ accept reject │
│ │ │ rejected │ │ │ │
│ │ └──────────────┘ ▼ ▼ │
│ │ ┌──────────────┐ │
│ │ │ accepted / │ │
│ │ │ rejected │ │
│ │ └──────────────┘ │
│ │ │
│ Note: rounds can continue indefinitely until accepted, │
│ rejected, or the proposal expires (expires_at reached) │
└─────────────────────────────────────────────────────────────────────┘
| Status | Description | Next valid actions |
proposed | Initial proposal submitted; awaiting response from other party | counter, accept, reject |
counter_proposed | Counter-proposal made; awaiting response from original proposer | counter, accept, reject |
accepted | Terms agreed — deal terms updated to reflect final negotiated values | (terminal) |
rejected | Proposal rejected; no further rounds | (terminal) |
expired | Proposal TTL elapsed without response | (terminal) |
Get the full negotiation history for a deal, including all proposals, counter-proposals, and outcomes.
| Parameter | Type | Description |
| deal_id required | string | The deal identifier |
Example
curl "https://api.salesbooth.com/v1/deal-negotiations?deal_id=deal_abc123" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"deal_id": "deal_abc123",
"status": "counter_proposed",
"total_rounds": 2,
"rounds": [
{
"round": 1,
"type": "proposal",
"proposed_by": "agent",
"proposed_terms": { "discount_percent": 15, "quantity": 10 },
"message": "Volume order — requesting 15% discount",
"expires_at": "2026-03-16T10:00:00Z",
"created_at": "2026-03-09T10:00:00Z"
},
{
"round": 2,
"type": "counter",
"proposed_by": "merchant",
"proposed_terms": { "discount_percent": 10, "quantity": 10 },
"message": "We can offer 10% for this volume",
"expires_at": "2026-03-18T10:00:00Z",
"created_at": "2026-03-09T10:05:00Z"
}
]
}
}
Get pricing intelligence for a deal in the context of a negotiation. Returns suggested counter-offer ranges, historical comparables, and confidence score.
Response
{
"error": false,
"data": {
"deal_id": "deal_abc123",
"suggested_counter": { "discount_percent": 8 },
"acceptable_range": { "discount_min": 5, "discount_max": 12 },
"confidence": "high",
"comparable_deals": 34,
"avg_accepted_discount": 7.8
}
}
Submit a negotiation action: propose, counter, accept, or reject.
| Field | Type | Description |
| action required | string | propose, counter, accept, reject |
| deal_id required | string | The deal identifier |
| proposed_terms | object | Terms to propose (required for propose and counter). Free-form key/value pairs: e.g. discount_percent, quantity, payment_terms |
| message | string | Optional message to accompany the proposal |
| expires_at | string | ISO 8601 expiry for this round (defaults to 7 days) |
| reason | string | Rejection reason (optional, used with reject) |
Example — propose terms
curl -X POST "https://api.salesbooth.com/v1/deal-negotiations?action=propose&deal_id=deal_abc123" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"proposed_terms": { "discount_percent": 15, "payment_terms": "net_30" },
"message": "Volume order — requesting 15% discount with net-30 terms",
"expires_at": "2026-03-19T00:00:00Z"
}'
Example — counter-propose
curl -X POST "https://api.salesbooth.com/v1/deal-negotiations?action=counter&deal_id=deal_abc123" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"proposed_terms": { "discount_percent": 10, "payment_terms": "net_15" },
"message": "We can offer 10% with net-15 terms"
}'
Example — accept
curl -X POST "https://api.salesbooth.com/v1/deal-negotiations?action=accept&deal_id=deal_abc123" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{}'
Example — reject
curl -X POST "https://api.salesbooth.com/v1/deal-negotiations?action=reject&deal_id=deal_abc123" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "reason": "Terms do not meet minimum margin requirements" }'
Get AI-generated counter-offer suggestions for the current negotiation round. Returns suggested terms, confidence scores, and data quality metrics. Fires a negotiation.suggestion_generated webhook.
| Field | Type | Description |
| deal_id required | string | The deal identifier |
| current_terms | object | The latest proposed terms (if omitted, uses the most recent round from history) |
Example
curl -X POST "https://api.salesbooth.com/v1/deal-negotiations?action=suggest&deal_id=deal_abc123" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"current_terms": { "discount_percent": 15, "payment_terms": "net_30" }
}'
Response
{
"error": false,
"data": {
"suggestions": [
{
"strategy": "balanced",
"proposed_terms": { "discount_percent": 10, "payment_terms": "net_15" },
"confidence": 0.82,
"rationale": "10% discount with net-15 closes 69% of similar deals; net-30 adds payment risk"
},
{
"strategy": "aggressive",
"proposed_terms": { "discount_percent": 7, "payment_terms": "net_7" },
"confidence": 0.61,
"rationale": "Maximum margin protection; 41% acceptance rate at this price point"
}
],
"data_quality": {
"comparable_deals": 52,
"confidence_level": "high"
}
}
}
Deal Templates
Reusable deal templates for programmatic offer generation. Create templates with pre-defined line items and terms, then instantiate them into real deals.
List deal templates with optional filters.
| Parameter | Type | Description |
| id | string | Retrieve a specific template |
| is_active | string | Filter: 1 (active, default), 0 (inactive) |
| search | string | Search by name or description |
| limit | integer | Max results, 1–100 (default: 50) |
| offset | integer | Pagination offset |
Example
curl https://api.salesbooth.com/v1/deal-templates \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Create a new deal template.
| Field | Type | Description |
| name required | string | Template name |
| description | string | Template description |
| category | string | Template category |
| default_terms | object | Default deal terms (currency, tax_rate, etc.) |
| line_items | array | Pre-defined line items with product_id, quantity, unit_price |
| metadata | object | Custom metadata |
Example
curl -X POST https://api.salesbooth.com/v1/deal-templates \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"name": "Enterprise Starter Pack",
"category": "enterprise",
"default_terms": { "currency": "USD", "tax_rate": 0.10 },
"line_items": [
{ "product_id": "prod_xxxxx", "quantity": 1, "unit_price": 999.00 }
]
}'
Instantiate a template into a real deal. Creates a deal with the template’s pre-defined line items and terms.
| Field | Type | Description |
| customer_id | string | Customer for the new deal |
| overrides | object | Override default terms (currency, tax_rate, etc.) |
Example
curl -X POST "https://api.salesbooth.com/v1/deal-templates?id=dtpl_xxxxx&action=create-deal" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "customer_id": "cust_xxxxx" }'
Update a deal template. Send only the fields you want to change.
Example
curl -X PATCH "https://api.salesbooth.com/v1/deal-templates?id=dtpl_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "name": "Updated Template Name" }'
Delete a deal template.
Example
curl -X DELETE "https://api.salesbooth.com/v1/deal-templates?id=dtpl_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
List the version history for a deal template. Each edit creates a new version; the full change history is retained.
Example
curl "https://api.salesbooth.com/v1/deal-templates?id=dtpl_xxxxx&action=versions" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": [
{ "version": 3, "created_at": "2026-05-10T12:00:00Z", "created_by": "user_xxxxx", "summary": "Updated pricing" },
{ "version": 2, "created_at": "2026-04-22T09:15:00Z", "created_by": "user_xxxxx", "summary": "Added line item" },
{ "version": 1, "created_at": "2026-04-01T08:00:00Z", "created_by": "user_xxxxx", "summary": "Initial version" }
]
}
Retrieve the full snapshot of a deal template at a specific version number.
| Parameter | Type | Description |
| version required | integer | Version number to retrieve |
Example
curl "https://api.salesbooth.com/v1/deal-templates?id=dtpl_xxxxx&action=version&version=2" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Compare two versions of a deal template and return a field-by-field diff of what changed between them.
| Parameter | Type | Description |
| from required | integer | Earlier version number |
| to required | integer | Later version number |
Example
curl "https://api.salesbooth.com/v1/deal-templates?id=dtpl_xxxxx&action=diff&from=1&to=3" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Roll back a deal template to a previous version. Creates a new version that is a copy of the specified historical version, preserving the full audit trail.
| Field | Type | Description |
| version required | integer | Version number to roll back to |
Example
curl -X POST "https://api.salesbooth.com/v1/deal-templates?id=dtpl_xxxxx&action=rollback" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "version": 2 }'
Delegations
Grant AI agents scoped, time-limited access with spending caps and delegation chains. Use delegations to give sub-agents constrained permissions without sharing your primary API key.
Who needs this: Use Delegations if you are building an AI agent that needs to spawn sub-agents or hand off tasks to other services while strictly limiting what those sub-agents are allowed to spend or do. Common use cases include procurement bots, approval-gate workflows, and multi-tenant SaaS where resellers act on behalf of customers.
When to skip this: If all API calls originate from your own server using a single API key, you don’t need delegations. They are only relevant when you are distributing authority across multiple keys, agents, or third parties.
Prerequisite: An API key with agent:execute scope and trust level ≥ 2 (Established).
Chain depth & spending caps: Delegations form a chain — Agent A can delegate a subset of its permissions to Agent B, which can sub-delegate to Agent C. The platform enforces:
- Downward only: A child delegation can never grant more permissions than the parent delegation it was created from.
- Spending caps cascade: Each transaction is checked against the per-transaction, daily, and monthly limits of every delegation in the chain. The most restrictive limit always wins.
- Expiry propagates: If any delegation in the chain expires or is revoked, all sub-delegations become invalid immediately.
Include delegation: Pass the X-Delegation-ID header on API requests or MCP calls to operate within a delegation’s spending limits and scope constraints.
List delegations you have created, or retrieve a specific delegation by ID. Use action=verify to check validity and remaining budget.
| Parameter | Type | Description |
| id | string | Retrieve a specific delegation |
| action | string | verify — check validity and budget; summary — dashboard summary; pending — incoming proposals (agent key only) |
| limit | integer | Max results (default: 50) |
| offset | integer | Pagination offset |
Example — verify delegation status and budget
curl "https://api.salesbooth.com/v1/delegations?id=del_xxxxx&action=verify" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"delegation_id": "del_xxxxx",
"status": "active",
"valid": true,
"allowed_actions": ["deals:read", "deals:write", "agent:negotiate"],
"spending": {
"max_transaction_amount": 5000.00,
"max_daily_amount": 25000.00,
"max_monthly_amount": null,
"spent_today": 3750.00,
"remaining_today": 21250.00,
"spent_this_month": 48200.00
},
"expires_at": "2026-06-01T00:00:00Z",
"grantee_key_id": "key_agent_xxxxx"
}
}
Validate the calling agent’s own active delegation and retrieve its allowed actions and spending limits. No id parameter is required — the delegation is resolved from the API key used for the request.
Example
curl "https://api.salesbooth.com/v1/delegations?action=check" \
-H "Authorization: Bearer sb_agent_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"valid": true,
"allowed_actions": ["deals:read", "agent:negotiate"],
"spending": {
"max_transaction_amount": 5000.00,
"spent_today": 1200.00,
"remaining_today": 3800.00
},
"expires_at": "2026-06-01T00:00:00Z"
}
}
Retrieve spending totals and limit utilisation for a delegation. Shows per-transaction, daily, and monthly usage against configured caps.
| Parameter | Type | Description |
| id required | string | Delegation ID |
Example
curl "https://api.salesbooth.com/v1/delegations?action=spending&id=del_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"delegation_id": "del_xxxxx",
"spent_today": 3750.00,
"spent_this_month": 48200.00,
"reserved_today": 500.00,
"max_daily_amount": 25000.00,
"max_monthly_amount": null,
"utilisation_daily_pct": 17.0,
"utilisation_monthly_pct": null
}
}
Retrieve per-delegation analytics including spending breakdown, deals created, ROI metrics, and a 30-day spending chart.
| Parameter | Type | Description |
| id required | string | Delegation ID |
Example
curl "https://api.salesbooth.com/v1/delegations?action=analytics&id=del_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"delegation_id": "del_xxxxx",
"total_deals_created": 14,
"total_spent": 62400.00,
"deals_by_status": { "signed": 12, "pending": 2 },
"spending_chart": [
{ "date": "2026-04-16", "amount": 4200.00 }
],
"roi_metrics": { "avg_deal_value": 4457.14 }
}
}
Returns a dashboard-level summary of all delegations for the authenticated tenant: active count, total daily and monthly budget utilisation, and pending approvals count.
Example
curl "https://api.salesbooth.com/v1/delegations?action=summary" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"active_count": 3,
"pending_approvals": 1,
"daily_budget_used_pct": 42,
"monthly_budget_used_pct": 18
}
}
List delegations that have transactions pending approval. Requires API key with delegations:read scope.
| Parameter | Type | Description |
| limit | integer | Max results (default: 50) |
| offset | integer | Pagination offset |
Example
curl "https://api.salesbooth.com/v1/delegations?action=pending" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"delegations": [
{
"delegation_id": "del_xxxxx",
"pending_approvals_count": 2,
"grantee_agent_key_id": "key_agent_xxxxx"
}
],
"pagination": { "total": 1, "limit": 50, "offset": 0 }
}
}
Retrieve details of a specific delegation proposal including its current status, negotiation history, and proposed terms.
| Parameter | Type | Description |
| id required | string | Delegation proposal ID (dprop_ prefix) |
Example
curl "https://api.salesbooth.com/v1/delegations?action=proposal&id=dprop_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"id": "dprop_xxxxx",
"status": "pending",
"proposer_api_key_id": "key_agent_aaaaa",
"target_api_key_id": "key_agent_bbbbb",
"proposed_actions": ["discover", "negotiate"],
"proposed_spending_limits": { "max_transaction_amount": 1000.00 },
"round": 1,
"expires_at": "2026-03-23T10:00:00Z"
}
}
Retrieve a paginated, filterable audit trail of all actions taken under a delegation. Supports date range and action/entity type filtering.
| Parameter | Type | Description |
| id required | string | Delegation ID |
| from_date | string | Filter from date (ISO 8601) |
| to_date | string | Filter to date (ISO 8601) |
| action_type | string | Filter by action type (e.g. deal_created, deal_signed) |
| entity_type | string | Filter by entity type (e.g. deal, customer) |
| limit | integer | Max results (default: 50) |
| offset | integer | Pagination offset |
Example
curl "https://api.salesbooth.com/v1/delegations?action=activity&id=del_xxxxx&from_date=2026-04-01" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"events": [
{
"id": "evt_xxxxx",
"action_type": "deal_created",
"entity_type": "deal",
"entity_id": "deal_xxxxx",
"amount": 4500.00,
"occurred_at": "2026-04-12T14:30:00Z"
}
],
"pagination": { "total": 42, "limit": 50, "offset": 0 }
}
}
Create a new delegation granting an agent API key a subset of your permissions with optional spending limits.
| Field | Type | Description |
| grantee_agent_key_id required | string | The agent API key ID to delegate to |
| allowed_actions required | array | Permitted actions (scope-based): deals:read, deals:write, agent:negotiate, deals:sign, customers:read, customers:write |
| max_transaction_amount | number | Per-transaction spending cap (null = no limit) |
| max_daily_amount | number | Daily spending cap (resets at midnight UTC) |
| max_monthly_amount | number | Monthly spending cap (resets on the 1st) |
| expires_at | string | Delegation expiry (ISO 8601, must be in the future) |
| description | string | Human-readable description of the delegation purpose (max 500 chars) |
| approval_threshold | number | Transaction amount above which approval is required |
| approval_steps | object | Multi-step approval workflow configuration |
| approval_timeout | integer | Hours before pending approval auto-expires (0–720) |
| auto_approve_policy | object | Conditions under which transactions are auto-approved |
| alert_threshold_pct | integer | Spending alert when daily/monthly usage reaches this percentage (1–100) |
| signing_authority_acknowledged | boolean | Required when allowed_actions includes sign authority. Confirms principal authorises agent to execute binding agreements. |
Example
curl -X POST https://api.salesbooth.com/v1/delegations \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"grantee_agent_key_id": "key_agent_xxxxx",
"allowed_actions": ["deals:read", "deals:write", "agent:negotiate"],
"max_transaction_amount": 5000.00,
"max_daily_amount": 25000.00,
"expires_at": "2026-06-01T00:00:00Z"
}'
Response (201)
{
"error": false,
"success": true,
"data": {
"delegation_id": "del_xxxxx",
"tenant_id": "tenant_abc123",
"grantor_type": "user",
"grantor_id": "42",
"grantee_agent_key_id": "key_agent_xxxxx",
"description": null,
"max_transaction_amount": "5000.00",
"max_daily_amount": "25000.00",
"max_monthly_amount": null,
"spent_today": "0.00",
"spent_this_month": "0.00",
"reserved_today": "0.00",
"reserved_this_month": "0.00",
"available_today": "25000.00",
"available_this_month": null,
"allowed_actions": ["deals:read", "deals:write", "agent:negotiate"],
"delegation_chain": [],
"expires_at": "2026-06-01 00:00:00",
"revoked_at": null,
"created_at": "2026-03-12 10:00:00",
"updated_at": "2026-03-12 10:00:00",
"approval_threshold": null,
"approval_steps": null,
"approval_timeout": null,
"auto_approve_policy": null,
"alert_threshold_pct": null
}
}
Update a delegation’s allowed actions, spending limits, or expiry. You can only reduce permissions, not expand beyond the original grant.
Example
curl -X PUT "https://api.salesbooth.com/v1/delegations?id=del_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "max_transaction_amount": 2500.00, "expires_at": "2026-05-01T00:00:00Z" }'
Revoke a delegation immediately. All child delegations in the chain are also invalidated.
Example
curl -X DELETE "https://api.salesbooth.com/v1/delegations?id=del_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Agent Proposal Flow
Agents can propose delegations to each other without requiring direct API access. The target agent receives the proposal and accepts, rejects, or counters it. The negotiation cycle repeats until both parties agree or the proposal expires.
List pending delegation proposals targeting this agent. Requires agent API key auth and delegations:read scope.
| Parameter | Type | Description |
| limit | integer | Max results (default: 50, max: 100) |
| offset | integer | Pagination offset (default: 0) |
Example
curl "https://api.salesbooth.com/v1/delegations/proposals" \
-H "Authorization: Bearer sb_agent_key_do_not_use"
Response
{
"error": false,
"data": {
"proposals": [
{
"id": "dprop_xxxxx",
"status": "pending",
"proposer_api_key_id": "key_agent_aaaaa",
"target_api_key_id": "key_agent_bbbbb",
"proposed_actions": ["discover", "negotiate"],
"proposed_spending_limits": { "max_transaction_amount": 1000.00 },
"proposed_duration_hours": 168,
"message": "Requesting delegation to negotiate deals on your behalf",
"round": 1,
"expires_at": "2026-03-23T10:00:00Z",
"created_at": "2026-03-16T10:00:00Z"
}
],
"pagination": { "total": 1, "limit": 50, "offset": 0 }
}
}
Propose a delegation to a target agent. Requires trust level 2+ and the delegate action in the proposer’s own delegation scope.
| Field | Type | Description |
| target_api_key_id required | string | API key ID of the target agent |
| proposed_actions required | array | Actions being proposed (e.g. discover, negotiate) |
| max_transaction_amount | number | Proposed per-transaction spending cap |
| max_daily_amount | number | Proposed daily spending cap |
| max_monthly_amount | number | Proposed monthly spending cap |
| proposed_duration_hours | integer | Delegation duration from acceptance (default: 168 = 1 week) |
| message | string | Optional message to the target agent explaining the request |
Example
curl -X POST https://api.salesbooth.com/v1/delegations/proposals \
-H "Authorization: Bearer sb_agent_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"target_api_key_id": "key_agent_bbbbb",
"proposed_actions": ["discover", "negotiate"],
"max_transaction_amount": 1000.00,
"proposed_duration_hours": 168,
"message": "Requesting delegation to negotiate deals on your behalf"
}'
Response (201)
{
"error": false,
"success": true,
"data": {
"id": "dprop_xxxxx",
"status": "pending",
"proposer_api_key_id": "key_agent_aaaaa",
"target_api_key_id": "key_agent_bbbbb",
"proposed_actions": ["discover", "negotiate"],
"proposed_spending_limits": { "max_transaction_amount": 1000.00 },
"proposed_duration_hours": 168,
"message": "Requesting delegation to negotiate deals on your behalf",
"round": 1,
"expires_at": "2026-03-23T10:00:00Z",
"created_at": "2026-03-16T10:00:00Z"
}
}
Accept an incoming delegation proposal. Creates an active delegation from the agreed terms. Requires agent API key auth.
Example
curl -X POST "https://api.salesbooth.com/v1/delegations/proposals/dprop_xxxxx/accept" \
-H "Authorization: Bearer sb_agent_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"proposal": { "id": "dprop_xxxxx", "status": "accepted", "resolved_at": "2026-03-16T10:05:00Z" },
"delegation": { "id": "del_yyyyy", "status": "active", "allowed_actions": ["discover", "negotiate"] }
}
}
Reject an incoming delegation proposal. The proposal is marked as rejected and no delegation is created.
| Field | Type | Description |
| reason | string | Optional rejection reason sent back to the proposer |
Example
curl -X POST "https://api.salesbooth.com/v1/delegations/proposals/dprop_xxxxx/reject" \
-H "Authorization: Bearer sb_agent_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "reason": "Spending limit too high for current context" }'
Counter-propose modified delegation terms. The target agent proposes a subset of the original terms. Creates a new proposal round; the original proposer can then accept, reject, or counter again.
| Field | Type | Description |
| proposed_actions required | array | Counter-proposed actions (must be subset of original) |
| max_transaction_amount | number | Counter-proposed per-transaction cap |
| max_daily_amount | number | Counter-proposed daily cap |
| max_monthly_amount | number | Counter-proposed monthly cap |
| proposed_duration_hours | integer | Counter-proposed duration in hours |
| message | string | Optional message explaining the counter-proposal |
Example
curl -X POST "https://api.salesbooth.com/v1/delegations/proposals/dprop_xxxxx/counter" \
-H "Authorization: Bearer sb_agent_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"proposed_actions": ["discover"],
"max_transaction_amount": 500.00,
"proposed_duration_hours": 72,
"message": "Accepting discover only with lower spending limit"
}'
Response (201)
{
"error": false,
"data": {
"id": "dprop_zzzzz",
"status": "pending",
"previous_proposal_id": "dprop_xxxxx",
"proposed_actions": ["discover"],
"proposed_spending_limits": { "max_transaction_amount": 500.00 },
"proposed_duration_hours": 72,
"round": 2,
"expires_at": "2026-03-23T10:05:00Z",
"created_at": "2026-03-16T10:05:00Z"
}
}
Using a Delegation
Pass the X-Delegation-ID header to operate within a delegation’s constraints. All spending is tracked against the delegation’s caps and propagated up the chain.
curl -X POST https://api.salesbooth.com/v1/deals \
-H "Authorization: Bearer sb_agent_key_do_not_use" \
-H "X-Delegation-ID: del_xxxxx" \
-H "Content-Type: application/json" \
-d '{ "customer_id": "cust_xxxxx", "currency": "USD" }'
# If the deal value would exceed max_transaction_amount, returns 429 spending_limit_exceeded
Product Families
Top-level groupings for organizing related products. Families define the structure for the product configurator.
List product families or retrieve a specific family.
| Parameter | Type | Description |
| id | string | Retrieve a specific family |
| status | string | Filter: active, archived |
| search | string | Search by name |
Example
curl https://api.salesbooth.com/v1/product-families \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Create a new product family.
| Field | Type | Description |
| name required | string | Family name |
| description | string | Family description |
| slug | string | URL-friendly slug |
| sort_order | integer | Display order |
| image_url | string | Family image URL |
| status | string | active or archived |
Example
curl -X POST https://api.salesbooth.com/v1/product-families \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "name": "Cloud Infrastructure", "description": "Cloud hosting and compute products" }'
Update a product family.
Example
curl -X PATCH "https://api.salesbooth.com/v1/product-families?id=pf_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "name": "Updated Family Name" }'
Archive a product family.
Example
curl -X DELETE "https://api.salesbooth.com/v1/product-families?id=pf_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Option Groups
Reusable configuration building blocks. Option groups define selectable options (e.g. colours, sizes, add-ons) that can be linked to products.
List option groups or retrieve a specific group with its options.
| Parameter | Type | Description |
| id | string | Retrieve a specific group |
| status | string | Filter: active, archived |
| search | string | Search by name |
| include_options | boolean | Include options in response |
Example
curl https://api.salesbooth.com/v1/option-groups?include_options=true \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Create a new option group.
| Field | Type | Description |
| name required | string | Group name (e.g. “Colour”, “Storage”) |
| description | string | Group description |
| selection_type | string | single or multiple |
| is_required | boolean | Whether selection is required |
| min_selections | integer | Minimum options the customer must select (0–100) |
| max_selections | integer | Maximum options the customer can select (0–100) |
| display_style | string | cards, dropdown, pills, swatches, checkboxes |
| sort_order | integer | Display order |
Example
curl -X POST https://api.salesbooth.com/v1/option-groups \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"name": "Storage Capacity",
"selection_type": "single",
"is_required": true,
"display_style": "cards"
}'
Options within Groups
Add an option to a group.
Example
curl -X POST "https://api.salesbooth.com/v1/option-groups?id=og_xxxxx&action=options" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "name": "256 GB", "price_modifier": 100.00, "sort_order": 1 }'
Update an option group or a specific option within it.
Example
curl -X PATCH "https://api.salesbooth.com/v1/option-groups?id=og_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "name": "Updated Group Name" }'
Archive an option group or a specific option.
Example
curl -X DELETE "https://api.salesbooth.com/v1/option-groups?id=og_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Bundle Rules
Define discount conditions when multiple options are selected together. Bundle rules automatically apply pricing incentives.
List bundle pricing rules, optionally filtered by product.
| Parameter | Type | Description |
| id | string | Retrieve a specific rule |
| product_id | string | Filter by product |
| is_active | boolean | Filter by active status |
Example
curl https://api.salesbooth.com/v1/bundle-rules?product_id=prod_xxxxx \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Create a bundle pricing rule.
| Field | Type | Description |
| name required | string | Rule name |
| product_id required | string | Product this rule applies to |
| option_ids required | array | Option IDs that trigger the bundle |
| discount_type required | string | percentage or fixed |
| discount_value required | number | Discount amount (percent or fixed) |
| min_options | integer | Minimum options needed (default: all) |
Example
curl -X POST https://api.salesbooth.com/v1/bundle-rules \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"name": "Full Suite Bundle",
"product_id": "prod_xxxxx",
"option_ids": ["opt_aaa", "opt_bbb", "opt_ccc"],
"discount_type": "percentage",
"discount_value": 15,
"min_options": 3
}'
Update a bundle pricing rule.
Example
curl -X PATCH "https://api.salesbooth.com/v1/bundle-rules?id=br_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "discount_value": 20 }'
Delete a bundle pricing rule.
Example
curl -X DELETE "https://api.salesbooth.com/v1/bundle-rules?id=br_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Compatibility Rules
Define requires, excludes, and includes_price relationships between options. Compatibility rules prevent invalid configurations.
List compatibility rules, optionally filtered by product or rule type.
| Parameter | Type | Description |
| id | string | Retrieve a specific rule |
| product_id | string | Filter by product |
| rule_type | string | Filter: requires, excludes, includes_price |
| source_option_id | string | Filter by source option |
Example
curl https://api.salesbooth.com/v1/compatibility-rules?product_id=prod_xxxxx \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Create a compatibility rule between two options.
| Field | Type | Description |
| source_option_id required | string | The triggering option |
| target_option_id required | string | The affected option |
| rule_type required | string | requires, excludes, or includes_price |
| product_id required | string | Product this rule applies to |
| message | string | User-facing message when rule triggers |
Example
curl -X POST https://api.salesbooth.com/v1/compatibility-rules \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"source_option_id": "opt_ssd",
"target_option_id": "opt_raid",
"rule_type": "requires",
"product_id": "prod_xxxxx",
"message": "RAID controller requires SSD storage"
}'
Update a compatibility rule.
Example
curl -X PATCH "https://api.salesbooth.com/v1/compatibility-rules?id=cr_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "message": "Updated compatibility message" }'
Delete a compatibility rule.
Example
curl -X DELETE "https://api.salesbooth.com/v1/compatibility-rules?id=cr_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Product Option Groups
Link option groups to specific products and manage per-product option availability overrides. Controls which option groups appear for a product and which individual options are available or hidden.
Get linked option groups and per-product option availability for a product.
| Parameter | Type | Description |
| product_id required | string | The product identifier |
| action | string | availability to list per-option availability overrides |
Example
curl "https://api.salesbooth.com/v1/product-option-groups?product_id=prod_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Link an option group to a product, or set per-option availability overrides.
| Field | Type | Description |
| product_id required | string | The product identifier |
| group_id | string | Option group to link (required when not setting availability) |
| sort_order_override | integer | Override display order for this product |
| is_required_override | boolean | Override whether the group is required |
| action | string | availability to set per-option availability (requires option_id and is_available) |
Example — Link option group
curl -X POST https://api.salesbooth.com/v1/product-option-groups \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"product_id": "prod_xxxxx",
"group_id": "grp_xxxxx",
"sort_order_override": 1,
"is_required_override": true
}'
Update link overrides or option availability for a product–option group association.
Example
curl -X PATCH https://api.salesbooth.com/v1/product-option-groups \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"product_id": "prod_xxxxx",
"group_id": "grp_xxxxx",
"sort_order_override": 2
}'
Unlink an option group from a product, or remove a per-option availability override.
| Field | Type | Description |
| product_id required | string | The product identifier |
| group_id | string | Option group to unlink |
Example
curl -X DELETE https://api.salesbooth.com/v1/product-option-groups \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"product_id": "prod_xxxxx",
"group_id": "grp_xxxxx"
}'
Product Rules
Retrieve an aggregate view of all configuration rules (compatibility and bundle rules) for a product, and validate option selections against those rules.
Get all active compatibility and bundle rules for a product in a single request.
| Parameter | Type | Description |
| product_id required | string | The product identifier |
Example
curl "https://api.salesbooth.com/v1/product-rules?product_id=prod_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Validate a configuration — a set of selected option IDs — against all rules for a product. Returns any violations with human-readable messages.
| Field | Type | Description |
| product_id required | string | The product identifier |
| selected_options required | array | Array of selected option IDs to validate |
Example
curl -X POST https://api.salesbooth.com/v1/product-rules \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"product_id": "prod_xxxxx",
"selected_options": ["opt_ssd_512", "opt_ram_32gb"]
}'
Response
{
"error": false,
"data": {
"valid": true,
"violations": [],
"price_adjustments": [
{ "reason": "Bundle discount: SSD + 32GB RAM", "amount": -50.00 }
]
}
}
Configuration (CPQ)
Unified CPQ (Configure, Price, Quote) API for AI agents and widget interactions. Get product schemas with rules, validate configurations, and calculate pricing.
Get the full configuration schema for a product, including option groups, compatibility rules, and bundle rules.
| Parameter | Type | Description |
| product_id required | string | Product identifier |
Example
curl https://api.salesbooth.com/v1/configuration?product_id=prod_xxxxx \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
List all product families for the configurator.
Example
curl https://api.salesbooth.com/v1/configuration?action=families \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Validate a set of selected options against the product’s configuration rules.
| Field | Type | Description |
| option_ids required | array | Array of selected option IDs |
Example
curl -X POST "https://api.salesbooth.com/v1/configuration?product_id=prod_xxxxx&action=validate" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "option_ids": ["opt_aaa", "opt_bbb"] }'
Response
{
"error": false,
"data": {
"valid": true,
"violations": [],
"bundles_applied": ["Full Suite Bundle"]
}
}
Calculate pricing for a configuration, including bundle discounts and option price modifiers.
| Field | Type | Description |
| option_ids required | array | Array of selected option IDs |
Example
curl -X POST "https://api.salesbooth.com/v1/configuration?product_id=prod_xxxxx&action=price" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "option_ids": ["opt_aaa", "opt_bbb"] }'
Response
{
"error": false,
"data": {
"base_price": 999.00,
"option_total": 200.00,
"bundle_discount": -59.85,
"subtotal": 1139.15,
"breakdown": [
{ "option_id": "opt_aaa", "name": "256 GB SSD", "price": 100.00 },
{ "option_id": "opt_bbb", "name": "RAID Controller", "price": 100.00 }
]
}
}
Webhooks
Subscribe to real-time events. Salesbooth will send an HTTP POST to your endpoint when events occur.
List all registered webhooks.
Register a new webhook.
| Field | Type | Description |
| url required | string | HTTPS endpoint URL to receive webhook events |
| events required | array | Event types to subscribe to (e.g. deal.created) |
| description | string | Optional human-readable description (max 255 chars) |
Example
curl -X POST https://api.salesbooth.com/v1/webhooks \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"url": "https://myapp.com/webhooks/salesbooth",
"events": ["deal.created"]
}'
New webhooks start as active by default. To pause a webhook, use PATCH with "status": "paused".
Update an existing webhook’s URL, subscribed events, status, or description.
| Field | Description |
| url | New endpoint URL |
| events | Array of event type strings to subscribe to |
| status | active or paused |
| description | Human-readable description |
Example
curl -X PATCH "https://api.salesbooth.com/v1/webhooks?id=wh_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"status": "paused",
"events": ["deal.created", "deal.closed", "payment.received"]
}'
Permanently remove a webhook registration. Future events will no longer be delivered to this endpoint.
Example
curl -X DELETE "https://api.salesbooth.com/v1/webhooks?id=wh_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Rotate the signing secret for a webhook.
List delivery attempts for a specific webhook with filtering and pagination.
| Parameter | Description |
| id required | Webhook ID to retrieve deliveries for |
| status | Filter by delivery status: pending, success, or failed |
| event_type | Filter by event type (e.g. deal.created) |
| limit | Number of results to return (default 50, max 100) |
| offset | Pagination offset (default 0) |
Example
curl "https://api.salesbooth.com/v1/webhooks/deliveries?id=wh_xxxxx&status=failed&limit=25" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"deliveries": [
{
"delivery_id": "whd_abc123",
"webhook_id": "wh_xxxxx",
"event_type": "deal.created",
"status": "failed",
"attempts": 3,
"response_code": 500,
"error_message": "Connection timeout",
"delivered_at": null,
"created_at": "2026-03-09T10:30:00Z"
}
],
"pagination": {
"total": 42,
"limit": 25,
"offset": 0,
"count": 1
}
}
}
List webhook event history with cursor-based pagination. Use since_sequence or since_timestamp to resume from a known position.
| Parameter | Description |
| since_sequence | Return events after this sequence number (cursor-based pagination) |
| since_timestamp | Return events after this ISO 8601 timestamp |
| event_type | Filter by event type (e.g. deal.created) |
| status | Filter by delivery status: pending, delivered, partially_delivered, or failed |
| limit | Number of results to return (1–100, default 50) |
Example
curl "https://api.salesbooth.com/v1/webhooks/events?since_sequence=1500&limit=50" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"events": [
{
"event_id": "evt_abc123",
"event_sequence": 1501,
"event_type": "deal.created",
"status": "delivered",
"created_at": "2026-03-09T10:30:00Z"
}
],
"cursor": {
"last_sequence": 1550,
"has_more": true
}
}
}
List deliveries that exhausted all retry attempts (maximum 3) and are now in the dead-letter queue. Use /webhooks/replay or /webhooks/retry to re-deliver them.
| Parameter | Description |
| event_type | Filter by event type |
| webhook_id | Filter by webhook ID |
| limit | Number of results to return (default 50) |
| offset | Pagination offset (default 0) |
Example
curl "https://api.salesbooth.com/v1/webhooks/dead_letter?webhook_id=wh_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"dead_letters": [
{
"delivery_id": "whd_abc123",
"webhook_id": "wh_xxxxx",
"event_id": "evt_abc123",
"event_type": "deal.created",
"payload": { "deal_id": "deal_xxx" },
"status": "failed",
"attempts": 3,
"max_attempts": 5,
"response_code": null,
"error_message": "Connection refused",
"is_replay": false,
"created_at": "2026-03-09T10:30:00Z"
}
],
"pagination": {
"total": 7,
"limit": 50,
"offset": 0,
"count": 1
}
}
}
Send a test event to a webhook endpoint to verify connectivity and your handler logic.
| Field | Type | Description |
| id required | query | Webhook ID to send the test event to |
| event_type | body | Event type to simulate (default: deal.created) |
Example
curl -X POST "https://api.salesbooth.com/v1/webhooks/test?id=wh_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"event_type": "deal.created"
}'
Response
{
"error": false,
"success": true,
"data": {
"success": true,
"response_code": 200,
"response_body": "OK",
"latency_ms": 45,
"error_message": null,
"event_type": "deal.created"
}
}
Re-deliver events from a given sequence number or timestamp to a webhook. Rate limited to 100 events per request. Replayed deliveries include an X-Salesbooth-Replayed: true header.
| Field | Description |
| webhook_id required | Target webhook to replay events to |
| since_sequence | Replay events after this sequence number |
| since_timestamp | Replay events after this ISO 8601 timestamp |
| event_type | Only replay a specific event type |
Example
curl -X POST https://api.salesbooth.com/v1/webhooks/replay \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"webhook_id": "wh_xxxxx",
"since_timestamp": "2026-03-09T00:00:00Z",
"event_type": "deal.created"
}'
Response
{
"error": false,
"success": true,
"data": {
"replayed": 42,
"webhook_id": "wh_xxxxx",
"has_more": false,
"events": [
{
"event_id": "evt_abc123",
"event_sequence": 1501,
"event_type": "deal.created",
"delivery_id": "whd_new456"
}
]
}
}
Manually retry a specific failed delivery. Resets the delivery to pending and attempts immediate re-delivery.
| Field | Description |
| delivery_id required | ID of the failed delivery to retry |
Example
curl -X POST https://api.salesbooth.com/v1/webhooks/retry \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"delivery_id": "whd_abc123"
}'
Response
{
"error": false,
"success": true,
"data": {
"delivery": {
"delivery_id": "whd_abc123",
"status": "success",
"attempts": 4,
"response_code": 200,
"error_message": null,
"retried_at": "2026-03-09T18:00:00Z"
}
}
}
Delete delivered webhook events older than the retention period. Safe to call from a cron job.
| Field | Description |
| retention_days | Days of events to retain (default 30) |
| batch_size | Maximum records to delete per run (default 10000) |
Example
curl -X POST https://api.salesbooth.com/v1/webhooks/cleanup \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"retention_days": 30,
"batch_size": 10000
}'
Response
{
"error": false,
"success": true,
"data": {
"cutoff_date": "2026-02-09T00:00:00Z",
"retention_days": 30,
"events_deleted": 4821,
"deliveries_deleted": 9203
}
}
Available Events
| Deal Events |
| deal.created | A new deal was created |
| deal.updated | A deal's fields were updated |
| deal.status_changed | A deal transitioned to a new status |
| deal.closed | A deal was closed |
| deal.fulfilled | A deal was fulfilled |
| deal.expired | A deal expired without being completed |
| deal.unsigned | A deal's signature was removed |
| deal.signature_added | A signature was added to a deal |
| deal.signature_timeout | A deal's signature request timed out |
| deal.item_added | A line item was added to a deal |
| deal.item_removed | A line item was removed from a deal |
| deal.item_updated | A line item on a deal was updated |
| deal.discount_applied | A discount was applied to a deal |
| deal.partially_accepted | A deal was partially accepted by the customer |
| deal.created_configured | A deal was created from a saved product configuration |
| deal.payment_received | A payment was received for a deal |
| deal.payment_failed | A payment attempt failed |
| deal.payment_refunded | A payment was refunded (full or partial) |
| deal.payment_overdue | A payment is overdue |
| deal.settlement_created | A settlement was created for a deal |
| deal.settlement_initiated | A settlement was initiated |
| deal.settlement_completed | A settlement completed successfully |
| deal.settlement_failed | A settlement failed |
| deal.settlement_all_completed | All settlements for a deal completed |
| deal.participant_invited | A participant was invited to a deal |
| deal.participant_accepted | A participant accepted their deal invitation |
| deal.participant_withdrawn | A participant withdrew from a deal |
| deal.participant_completed | A participant completed their deal obligations |
Negotiation Events — Legacy (deal.*) Maintained for backward compatibility. Both families fire simultaneously. |
| deal.negotiation_proposed | A negotiation proposal was made (minimal payload) |
| deal.negotiation_counter_proposed | A counter-proposal was made (minimal payload) |
| deal.negotiation_accepted | A negotiation proposal was accepted (minimal payload) |
| deal.negotiation_rejected | A negotiation proposal was rejected (minimal payload) |
Negotiation Events — Current (negotiation.*) Richer payloads. Prefer these for new integrations. |
| negotiation.proposed | Initial proposal submitted — includes proposer, terms, and expires_at |
| negotiation.countered | Counter-proposal made — includes round_number, previous_terms, and new_terms for diffing |
| negotiation.accepted | Proposal accepted — includes final_terms and total_rounds |
| negotiation.rejected | Proposal rejected — includes reason and round_number |
| negotiation.expired | A negotiation round expired without resolution |
| negotiation.suggestion_generated | AI generated a negotiation suggestion |
| Contract Events |
| contract.signed | A contract was signed |
| contract.activated | A contract was activated |
| contract.terminated | A contract was terminated |
| contract.tamper_detected | A tamper attempt was detected on a contract |
| contract.auto_renewed | A contract was automatically renewed |
| contract.renewal_failed | A contract auto-renewal attempt failed |
| contract.renewal_opted_out | A customer opted out of contract auto-renewal |
| contract.renewal_upcoming | A contract renewal is approaching |
| Subscription Events |
| subscription.created | A subscription was created |
| subscription.renewed | A subscription was renewed |
| subscription.renewal_upcoming | A subscription renewal is approaching |
| subscription.paused | A subscription was paused |
| subscription.resumed | A paused subscription was resumed |
| subscription.cancelled | A subscription was cancelled |
| subscription.upgraded | A subscription was upgraded to a higher tier |
| subscription.downgraded | A subscription was downgraded to a lower tier |
| subscription.changed | A subscription was modified |
| subscription.past_due | A subscription payment is past due |
| subscription.suspended | A subscription was suspended due to non-payment |
| subscription.cycle_changed | A subscription billing cycle was changed |
| subscription.payment_failed | A subscription payment attempt failed |
| subscription.payment_retried | A failed subscription payment was retried |
| subscription.proration_credit | A proration credit was applied to a subscription |
| subscription.meter_added | A usage meter was added to a subscription |
| subscription.meter_removed | A usage meter was removed from a subscription |
| subscription.usage_recorded | Usage was recorded against a subscription meter |
| subscription.usage_charges_applied | Usage charges were applied to a subscription |
| Customer Events |
| customer.created | A new customer was created |
| customer.updated | A customer record was updated |
| customer.deleted | A customer was deleted |
| Booking Events |
| booking.created | A new booking was created |
| booking.cancelled | A booking was cancelled |
| booking.completed | A booking was completed |
| booking.no_show | A customer did not show up for a booking |
| booking.held | A booking slot was placed on hold |
| booking.hold_expired | A booking hold expired without confirmation |
| booking.rescheduled | A booking was rescheduled to a new time |
| Billing Events |
| billing.credit_added | Credits were added to the account balance |
| billing.credit_deducted | Credits were deducted from the account balance |
| billing.auto_topup | An automatic top-up was triggered |
| billing.low_balance | Account credit balance dropped below the threshold |
| billing.widget_degraded | The widget entered degraded mode due to insufficient credits |
| Delegation Events |
| delegation.proposed | A delegation proposal was submitted |
| delegation.accepted | A delegation proposal was accepted |
| delegation.rejected | A delegation proposal was rejected |
| delegation.countered | A counter-proposal was made to a delegation |
| delegation.granted | A delegation was granted to an agent |
| delegation.revoked | A delegation was revoked |
| delegation.expired | A delegation expired |
| delegation.budget_warning | A delegation is approaching its budget limit |
| Agent Events |
| agent.approval_required | An agent action requires human approval |
| agent.approval_resent | An approval request was resent |
| agent.approval_escalated | An approval request was escalated |
| agent.anomaly_detected | Anomalous agent behaviour was detected |
| agent.spending_ceiling | An agent reached its spending ceiling |
| agent.trust_cap_exceeded | An agent exceeded its trust cap |
| agent.trust.level_changed | An agent's trust level changed |
| agent.trust.abuse_detected | Abuse was detected from a trusted agent |
| agent.trust.decay_warning | An agent's trust score is decaying |
| agent.trust.credential_issued | A trust credential was issued to an agent |
| agent.trust.credential_presented | An agent presented a trust credential |
| agent.trust.credential_revoked | An agent's trust credential was revoked |
| Agent Workflow Events |
| agent.workflow.planned | An agent workflow plan was created |
| agent.workflow.approved | An agent workflow was approved to proceed |
| agent.workflow.completed | An agent workflow completed successfully |
| agent.workflow.failed | An agent workflow failed |
| agent.workflow.cancelled | An agent workflow was cancelled |
| agent.workflow.degraded | An agent workflow entered degraded mode |
| agent.workflow.step_completed | A step in an agent workflow completed |
| agent.workflow.step_retried | A workflow step was retried |
| agent.workflow.dead_lettered | A workflow step was moved to the dead-letter queue |
| Escrow Events |
| escrow.created | An escrow was created |
| escrow.released | An escrow was released |
| escrow.refunded | An escrow was refunded |
| escrow.condition_fulfilled | An escrow condition was fulfilled |
| escrow.reauthorization_pending | An escrow requires reauthorization |
| escrow.reauthorized | An escrow was successfully reauthorized |
| escrow.reauthorization_failed | An escrow reauthorization attempt failed |
| Federation Events |
| federation.settlement_completed | A cross-tenant federated settlement completed |
| federation.settlement_failed | A cross-tenant federated settlement failed |
| federation.escrow_disputed | A federated escrow was disputed |
| federation.escrow_expired | A federated escrow expired |
| Product & Catalogue Events |
| product_family.created | A product family was created |
| product_family.updated | A product family was updated |
| product_family.deleted | A product family was deleted |
| option_group.created | An option group was created |
| option_group.updated | An option group was updated |
| option_group.deleted | An option group was deleted |
| option.created | A product option was created |
| option.updated | A product option was updated |
| option.deleted | A product option was deleted |
| bundle_rule.created | A bundle rule was created |
| bundle_rule.updated | A bundle rule was updated |
| bundle_rule.deleted | A bundle rule was deleted |
| compatibility_rule.created | A compatibility rule was created |
| compatibility_rule.updated | A compatibility rule was updated |
| compatibility_rule.deleted | A compatibility rule was deleted |
| Saved Configuration Events |
| saved_config.created | A product configuration was saved |
| saved_config.viewed | A saved configuration was viewed |
| saved_config.converted | A saved configuration was converted to a deal |
| saved_config.expiring | A saved configuration is about to expire |
| saved_config.expired | A saved configuration expired |
| Portal Events |
| portal.payment_completed | A payment was completed via the customer portal |
| portal.contract_signed | A contract was signed via the customer portal |
| portal.change_requested | A change was requested via the customer portal |
| Consent Events |
| consent.expiring_soon | A customer consent record is about to expire |
| consent.expired | A customer consent record expired |
| Tenant & Trust Events |
| tenant.trust_level_changed | A tenant's trust level changed |
| tenant.trust_promoted | A tenant was promoted to a higher trust tier |
| tenant.trust_level_decay_warning | A tenant's trust level is decaying |
| trust.demoted | A trust entity was demoted to a lower tier |
| trust.fraud_signal | A fraud signal was raised against a trust entity |
| Workflow Events |
| workflow.step_approved | A workflow step was approved |
| workflow.sell.proposal_received | A sell workflow received a proposal |
| workflow.fulfill.delivered | A fulfillment workflow delivered its outcome |
| System & Infrastructure Events |
| job.completed | A background job completed |
| job.failed | A background job failed |
| queue.depth_alert | A job queue depth exceeded its alert threshold |
| system.job_dead_letter | A job was moved to the dead-letter queue |
| service.circuit_opened | A circuit breaker opened due to repeated failures |
| service.circuit_closed | A circuit breaker closed after recovery |
| circuit-breaker.backoff-increased | A circuit breaker increased its backoff interval |
| encryption.rekey_completed | An encryption re-key operation completed |
| security.csp_spike | A spike in CSP violation reports was detected |
| Other Events |
| payment.received | A payment was received |
| credential.issued | A verifiable credential was issued |
| api_key.rotated | An API key was rotated |
Webhook Payload Format
All webhook payloads follow the same structure. Each delivery includes an X-Salesbooth-Signature header for verification.
Example Payload — deal.created
{
"id": "evt_abc123",
"event": "deal.created",
"created_at": "2026-03-09T10:30:00Z",
"data": {
"id": "deal_abc123",
"customer_id": "cust_xxxxx",
"status": "draft",
"currency": "USD",
"subtotal": "0.00",
"total": "0.00",
"created_at": "2026-03-09T10:30:00Z"
}
}
Example Payload — deal.status_changed
{
"id": "evt_def456",
"event": "deal.status_changed",
"created_at": "2026-03-09T11:00:00Z",
"data": {
"id": "deal_abc123",
"previous_status": "draft",
"new_status": "in_progress",
"changed_at": "2026-03-09T11:00:00Z"
}
}
Example Payload — deal.payment_received
{
"id": "evt_ghi789",
"event": "deal.payment_received",
"created_at": "2026-03-09T12:00:00Z",
"data": {
"deal_id": "deal_abc123",
"amount": "1099.00",
"currency": "USD",
"payment_intent_id": "pi_xxxxx",
"status": "succeeded"
}
}
Example Payload — customer.created
{
"id": "evt_jkl012",
"event": "customer.created",
"created_at": "2026-03-09T10:00:00Z",
"data": {
"id": "cust_xxxxx",
"company": "Acme Corp",
"status": "active",
"created_at": "2026-03-09T10:00:00Z"
}
}
Example Payload — contract.signed
{
"id": "evt_mno345",
"event": "contract.signed",
"created_at": "2026-03-09T13:00:00Z",
"data": {
"id": "contract_xxxxx",
"deal_id": "deal_abc123",
"customer_id": "cust_xxxxx",
"signed_by": "customer",
"signed_at": "2026-03-09T13:00:00Z",
"signature_method": "ed25519"
}
}
Example Payload — negotiation.proposed
{
"id": "evt_pqr678",
"event": "negotiation.proposed",
"created_at": "2026-03-09T14:00:00Z",
"data": {
"deal_id": "deal_abc123",
"round_number": 1,
"proposer": "agent",
"proposed_terms": { "discount_percent": 15, "payment_terms": "net_30" },
"message": "Volume order — requesting 15% discount",
"expires_at": "2026-03-16T14:00:00Z"
}
}
Example Payload — negotiation.countered
{
"id": "evt_stu901",
"event": "negotiation.countered",
"created_at": "2026-03-09T15:00:00Z",
"data": {
"deal_id": "deal_abc123",
"round_number": 2,
"proposer": "merchant",
"previous_terms": { "discount_percent": 15, "payment_terms": "net_30" },
"new_terms": { "discount_percent": 10, "payment_terms": "net_15" },
"message": "We can offer 10% with net-15 terms",
"expires_at": "2026-03-18T15:00:00Z"
}
}
Example Payload — negotiation.accepted
{
"id": "evt_vwx234",
"event": "negotiation.accepted",
"created_at": "2026-03-09T16:00:00Z",
"data": {
"deal_id": "deal_abc123",
"total_rounds": 2,
"final_terms": { "discount_percent": 10, "payment_terms": "net_15" },
"accepted_by": "agent",
"accepted_at": "2026-03-09T16:00:00Z"
}
}
Example Payload — subscription.created
{
"id": "evt_yza567",
"event": "subscription.created",
"created_at": "2026-03-09T17:00:00Z",
"data": {
"deal_id": "deal_abc123",
"billing_cycle": "monthly",
"status": "active",
"next_renewal_at": "2026-04-09T17:00:00Z",
"amount": "99.00",
"currency": "USD"
}
}
Example Payload — subscription.past_due
{
"id": "evt_bcd890",
"event": "subscription.past_due",
"created_at": "2026-04-09T17:05:00Z",
"data": {
"deal_id": "deal_abc123",
"amount": "99.00",
"currency": "USD",
"failure_reason": "card_declined",
"grace_period_ends_at": "2026-04-16T17:05:00Z",
"retry_count": 1
}
}
Example Payload — escrow.created
{
"id": "evt_efg123",
"event": "escrow.created",
"created_at": "2026-03-10T10:00:00Z",
"data": {
"id": "escrow_xxxxx",
"deal_id": "deal_abc123",
"amount": "2500.00",
"currency": "USD",
"release_condition": "delivery_confirmed",
"expires_at": "2026-06-10T10:00:00Z"
}
}
Example Payload — subscription.renewed
{
"id": "evt_hij456",
"event": "subscription.renewed",
"created_at": "2026-04-09T17:00:00Z",
"data": {
"deal_id": "deal_abc123",
"renewal_deal_id": "deal_def456",
"billing_cycle": "monthly",
"base_amount": "99.00",
"metered_amount": "2.55",
"total_amount": "101.55",
"currency": "USD",
"next_renewal_at": "2026-05-09T17:00:00Z"
}
}
Example Payload — subscription.cancelled
{
"id": "evt_klm789",
"event": "subscription.cancelled",
"created_at": "2026-03-12T10:00:00Z",
"data": {
"deal_id": "deal_abc123",
"cancelled_at": "2026-03-12T10:00:00Z",
"effective_at": "2026-04-09T17:00:00Z",
"end_of_period": true,
"reason": "Customer requested cancellation"
}
}
Signature Verification
Every webhook delivery includes two headers: X-Salesbooth-Signature (v1= + HMAC-SHA256 of the timestamp + raw body) and X-Salesbooth-Timestamp (Unix timestamp of delivery). Always verify both to prevent replay attacks. Reject events where the timestamp is older than 300 seconds (5 minutes).
const crypto = require('crypto');
const TOLERANCE_SECONDS = 300; // 5 minutes
function verifyWebhook(rawBody, signature, timestamp, secret) {
// 1. Reject stale events
const age = Math.floor(Date.now() / 1000) - parseInt(timestamp, 10);
if (age > TOLERANCE_SECONDS) throw new Error('Webhook timestamp too old');
// 2. Compute expected signature: v1= + HMAC-SHA256(timestamp.body, secret)
const payload = `${timestamp}.${rawBody}`;
const expected = 'v1=' + crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
// 3. Constant-time comparison (signature starts with "v1=" — not valid hex)
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) throw new Error('Invalid signature');
return true;
}
// Express.js example
app.post('/webhooks/salesbooth', express.raw({ type: 'application/json' }), (req, res) => {
try {
verifyWebhook(
req.body.toString(),
req.headers['x-salesbooth-signature'],
req.headers['x-salesbooth-timestamp'],
process.env.WEBHOOK_SECRET
);
const event = JSON.parse(req.body);
console.log('Verified event:', event.event, event.id);
res.sendStatus(200);
} catch (err) {
console.error('Webhook verification failed:', err.message);
res.sendStatus(400);
}
});
Audit Trail
Every entity has an immutable, cryptographically chained audit trail. Entries cannot be modified or deleted.
Retrieve the audit trail for an entity.
| Parameter | Description |
| entity_type required | deal, contract, customer, product |
| entity_id required | The entity identifier |
| limit | Max results, 1–100 (default: 50) |
| offset | Pagination offset |
Verify the cryptographic hash chain integrity of an audit trail. Returns whether all entries are intact and untampered.
Export the audit trail as a self-contained compliance evidence package. Requires the audit:export scope. Supports three export modes: single entity (provide entity_type + entity_id), date range (provide start_date + end_date), or bulk by type (provide entity_type alone). Exports include a verification_hash (SHA-256) covering the entire payload for tamper detection. Use format=csv to receive a spreadsheet-compatible download.
| Parameter | Type | Description |
| entity_type | string | deal, contract, customer, or product |
| entity_id | string | Specific entity ID (required with entity_type for single-entity export) |
| start_date | string | Start of date range (Y-m-d or Y-m-d H:i:s) |
| end_date | string | End of date range (Y-m-d or Y-m-d H:i:s) |
| format | string | json (default) or csv |
| limit | integer | Max entries to return, 1–10000 (default: 1000) |
| offset | integer | Pagination offset |
Single entity export
curl "https://api.salesbooth.com/v1/audit/export?entity_type=deal&entity_id=deal_abc123" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Date range export (CSV)
curl "https://api.salesbooth.com/v1/audit/export?start_date=2026-01-01&end_date=2026-03-31&format=csv" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-o audit-q1-2026.csv
Response (JSON)
{
"error": false,
"data": {
"export_version": "1.0",
"exported_at": "2026-03-18T10:00:00Z",
"tenant_id": "tenant_xxxxx",
"entity_type": "deal",
"entity_id": "deal_abc123",
"audit_entries": [
{
"id": "audit_001",
"action": "deal.created",
"actor": "user_xxxxx",
"created_at": "2026-03-10T09:00:00Z",
"entry_hash": "b4e2a1..."
}
],
"verification_hash": "sha256:c9f3b2..."
}
}
Intelligence
AI-powered deal scoring, pricing analytics, risk assessment, pipeline forecasting, and model calibration. All endpoints require the deals:read scope; config write operations additionally require intelligence:write.
Scoring model: Each deal score (0–100) is a weighted composite of configurable factors. Default weights: deal_size (25%), customer_history (30%), pipeline_stage (20%), engagement (15%), time_in_stage (10%). Weights must sum to 1.0 and can be overridden per tenant via PATCH ?type=config.
AI-generated deal score (0–100) with factor breakdown, recommendations, and risk flags.
| Parameter | Type | Description |
| deal_id required | string | The deal to score |
Example
curl "https://api.salesbooth.com/v1/intelligence?type=score&deal_id=deal_abc123" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"deal_id": "deal_abc123",
"score": 74,
"confidence": "high",
"label": "Good",
"factors": {
"deal_size": { "score": 80, "weight": 0.25, "contribution": 20 },
"customer_history": { "score": 70, "weight": 0.30, "contribution": 21 },
"pipeline_stage": { "score": 60, "weight": 0.20, "contribution": 12 },
"engagement": { "score": 85, "weight": 0.15, "contribution": 12.75 },
"time_in_stage": { "score": 67, "weight": 0.10, "contribution": 6.7 }
},
"recommendations": [
{ "type": "discount", "amount": 5, "rationale": "Volume threshold reached — 5% discount increases close probability by ~12%" }
],
"risk_flags": [],
"scored_at": "2026-03-12T10:00:00Z"
}
}
AI-suggested optimal price for a deal based on comparable historical deals, customer segment, and pipeline data.
Response
{
"error": false,
"data": {
"deal_id": "deal_abc123",
"suggested_price": 4750.00,
"current_price": 5000.00,
"confidence": "medium",
"rationale": "Similar deals with this customer segment close 23% more often at 4,500–5,000 range",
"comparable_deals": 47,
"win_rate_at_suggested": 0.71,
"win_rate_at_current": 0.58
}
}
Risk assessment for a specific deal. Returns identified risk factors, severity levels, and mitigation suggestions.
Example
curl "https://api.salesbooth.com/v1/intelligence?type=risk&deal_id=deal_abc123" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"deal_id": "deal_abc123",
"overall_risk": "medium",
"risk_score": 42,
"factors": [
{
"factor": "time_in_stage",
"severity": "high",
"description": "Deal has been in 'in_progress' for 18 days (median: 7 days)",
"mitigation": "Follow up with customer — consider offering a limited-time incentive"
},
{
"factor": "deal_size",
"severity": "low",
"description": "Deal value is within normal range for this customer segment",
"mitigation": null
}
],
"churn_probability": 0.31,
"assessed_at": "2026-03-12T10:00:00Z"
}
}
Predicted close date and probability distribution for a specific deal based on pipeline velocity and historical patterns.
Response
{
"error": false,
"data": {
"deal_id": "deal_abc123",
"predicted_close_date": "2026-04-08",
"confidence_interval": {
"p25": "2026-03-28",
"p50": "2026-04-08",
"p75": "2026-04-22"
},
"close_probability_30d": 0.68,
"close_probability_60d": 0.84,
"methodology": "Gradient boosted on 2,400 historical deals in this pipeline stage"
}
}
Aggregate revenue forecast for all active pipeline deals. Sums probability-weighted close amounts by period.
| Parameter | Type | Description |
| period | string | 30d, 60d, 90d, or all (default: all) |
Response
{
"error": false,
"data": {
"period": "90d",
"forecast_revenue": 284500.00,
"weighted_pipeline": 142750.00,
"currency": "USD",
"by_stage": {
"in_progress": { "count": 23, "total_value": 187000.00, "weighted": 93500.00 },
"pending_signature": { "count": 8, "total_value": 97500.00, "weighted": 87750.00 }
},
"generated_at": "2026-03-12T10:00:00Z"
}
}
Win probability calibration curve — maps deal scores to observed win rates. Use this to understand how accurate the scoring model is for your data.
Response
{
"error": false,
"data": {
"buckets": [
{ "score_range": "0-20", "avg_score": 12, "win_rate": 0.08, "sample_size": 34 },
{ "score_range": "21-40", "avg_score": 31, "win_rate": 0.22, "sample_size": 67 },
{ "score_range": "41-60", "avg_score": 51, "win_rate": 0.45, "sample_size": 112 },
{ "score_range": "61-80", "avg_score": 71, "win_rate": 0.69, "sample_size": 89 },
{ "score_range": "81-100","avg_score": 88, "win_rate": 0.86, "sample_size": 54 }
],
"calibration_error": 0.04,
"total_deals": 356
}
}
Historical scoring snapshots for a deal. Useful for charting score trends and correlating score changes with deal events.
| Parameter | Type | Description |
| deal_id required | string | The deal to fetch history for |
| limit | integer | Max snapshots (default: 20) |
Response
{
"error": false,
"data": {
"deal_id": "deal_abc123",
"history": [
{ "score": 62, "scored_at": "2026-03-01T09:00:00Z", "trigger": "deal_created" },
{ "score": 68, "scored_at": "2026-03-05T14:30:00Z", "trigger": "item_added" },
{ "score": 74, "scored_at": "2026-03-09T10:00:00Z", "trigger": "negotiation_accepted" }
]
}
}
Model calibration report for the current scoring configuration. Returns accuracy metrics and weight optimization suggestions based on your tenant’s deal history.
Response
{
"error": false,
"data": {
"accuracy": 0.79,
"brier_score": 0.14,
"deals_analyzed": 356,
"current_weights": {
"deal_size": 0.25, "customer_history": 0.30,
"pipeline_stage": 0.20, "engagement": 0.15, "time_in_stage": 0.10
},
"suggested_weights": {
"deal_size": 0.20, "customer_history": 0.35,
"pipeline_stage": 0.25, "engagement": 0.10, "time_in_stage": 0.10
},
"estimated_accuracy_improvement": 0.04
}
}
Pricing intelligence across all products — average deal sizes, price distribution, and discount patterns by product.
Example
curl "https://api.salesbooth.com/v1/intelligence?type=pricing" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Pipeline analytics — deals by stage, conversion rates, average time-in-stage, and velocity metrics.
Deal outcome analytics — win/loss rates, average deal size by outcome, revenue attributed, and time-to-close by segment.
Common patterns in lost deals. Clusters similar loss reasons to identify systemic issues (e.g. price too high, slow response, competitor).
Get the current scoring configuration (weights, thresholds, enabled factors).
Update deal scoring weights and thresholds. Requires intelligence:write scope. Weights must sum to 1.0.
| Field | Type | Description |
| weights | object | Keys: deal_size, customer_history, pipeline_stage, engagement, time_in_stage. Values must sum to 1.0. |
| thresholds | object | Score thresholds for label assignment: good (default: 70), fair (default: 40), poor (below 40) |
Example
curl -X PATCH "https://api.salesbooth.com/v1/intelligence?type=config" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"weights": {
"deal_size": 0.20,
"customer_history": 0.35,
"pipeline_stage": 0.25,
"engagement": 0.10,
"time_in_stage": 0.10
},
"thresholds": { "good": 72, "fair": 45 }
}'
Backtest proposed scoring weights against your historical deal data before applying them. Returns accuracy comparison between proposed and current configuration.
| Field | Type | Description |
| weights required | object | Proposed weight configuration to test (must sum to 1.0) |
Example
curl -X POST "https://api.salesbooth.com/v1/intelligence?type=backtest" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"weights": {
"deal_size": 0.20, "customer_history": 0.35,
"pipeline_stage": 0.25, "engagement": 0.10, "time_in_stage": 0.10
}
}'
Response
{
"error": false,
"data": {
"proposed_accuracy": 0.83,
"current_accuracy": 0.79,
"improvement": 0.04,
"deals_tested": 356,
"top_gains": [
{ "stage": "pending_signature", "accuracy_delta": 0.09 }
]
}
}
Returns all deals within a specific pipeline stage, enriched with the latest AI score and win probability. Useful for building stage-level kanban views or identifying high-value deals that need attention.
| Parameter | Type | Description |
| stage required | string | Pipeline stage to query. One of: draft, in_progress, pending_payment, pending_signature, awaiting_signatures, closed, cancelled, expired |
Example
curl "https://api.salesbooth.com/v1/intelligence?type=pipeline_deals&stage=in_progress" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"stage": "in_progress",
"count": 3,
"deals": [
{
"deal_id": "deal_abc123",
"title": "Enterprise Plan — Acme Corp",
"total": 12500.00,
"status": "in_progress",
"created_at": "2026-03-01T09:00:00Z",
"customer_name": "Acme Corp",
"score": 74,
"win_probability": 0.68,
"days_since_update": 3
}
]
}
}
Bulk pricing suggestions for all active deals that are currently under-discounted compared to similar deals that closed successfully. Returns up to 20 deals ranked by priority (lowest win probability first). Only deals where the suggested discount is ≥5% and there are ≥3 comparable closed deals are included.
Example
curl "https://api.salesbooth.com/v1/intelligence?type=pricing_suggestions_bulk" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"count": 2,
"suggestions": [
{
"deal_id": "deal_abc123",
"title": "Enterprise Plan — Acme Corp",
"total": 12500.00,
"currency": "USD",
"product_name": "Enterprise Plan",
"current_discount": 0,
"suggested_discount": 8.5,
"avg_winning_discount": 8.5,
"win_probability": 0.42,
"probability_lift": 0.034,
"score": 51,
"reason": "Products like \"Enterprise Plan\" close at 8.5% avg discount on similar deals"
}
]
}
}
Analytics on AI suggestion acceptance and rejection rates. Shows which suggestion types are being acted on, their impact on deal outcomes, and trends over time. Use this to evaluate the effectiveness of AI recommendations for your pipeline.
| Parameter | Type | Description |
| days | integer | Lookback window in days, 7–365 (default: 90) |
Example
curl "https://api.salesbooth.com/v1/intelligence?type=suggestion_analytics&days=90" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"period_days": 90,
"total_suggestions": 148,
"accepted": 62,
"rejected": 41,
"pending": 45,
"acceptance_rate": 0.60,
"by_type": {
"discount": { "total": 89, "accepted": 41, "acceptance_rate": 0.62 },
"follow_up": { "total": 35, "accepted": 14, "acceptance_rate": 0.54 },
"upsell": { "total": 24, "accepted": 7, "acceptance_rate": 0.44 }
},
"outcome_impact": {
"accepted_deal_win_rate": 0.71,
"rejected_deal_win_rate": 0.48
}
}
}
AI-suggested counter-terms for deal negotiations. Analyses the current deal terms and buyer history to recommend revised terms that balance win probability with revenue protection. Particularly useful in agent integrations and automated negotiation workflows.
| Parameter | Type | Description |
| deal_id required | string | The deal to generate counter-terms for |
| current_terms | string | JSON-encoded object of the buyer's proposed terms to counter (optional). If omitted, suggestions are based on the deal's current state. |
Example
curl "https://api.salesbooth.com/v1/intelligence?type=counter_terms&deal_id=deal_abc123" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Example with buyer terms
curl -G "https://api.salesbooth.com/v1/intelligence" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
--data-urlencode "type=counter_terms" \
--data-urlencode "deal_id=deal_abc123" \
--data-urlencode 'current_terms={"discount_pct":15,"payment_terms":"net60"}'
Response
{
"error": false,
"data": {
"deal_id": "deal_abc123",
"counter_terms": [
{
"field": "discount_pct",
"buyer_proposed": 15,
"counter_offer": 8,
"rationale": "8% is within the range that closes 73% of deals in this segment; 15% reduces margin below threshold"
},
{
"field": "payment_terms",
"buyer_proposed": "net60",
"counter_offer": "net30",
"rationale": "net30 is standard for this customer tier; offer net45 as a concession if needed"
}
],
"win_probability_if_accepted": 0.71,
"generated_at": "2026-03-12T10:00:00Z"
}
}
SDK Example — Score a Deal
const { SalesBooth } = require('@salesbooth/node');
const sb = new SalesBooth({ apiKey: 'sb_test_example_key_do_not_use' });
// Score a deal and get recommendations
const result = await sb.intelligence.scoreDeal('deal_abc123');
console.log('Score:', result.score); // 74
console.log('Confidence:', result.confidence); // "high"
result.recommendations.forEach(rec => {
console.log(`Recommendation: ${rec.type} ${rec.amount}% — ${rec.rationale}`);
});
// Get pricing suggestion
const suggestion = await sb.intelligence.getPricingSuggestion('deal_abc123');
console.log('Suggested price:', suggestion.suggested_price);
// Get risk assessment
const risk = await sb.intelligence.assessRisk('deal_abc123');
if (risk.overall_risk === 'high') {
console.warn('High-risk deal:', risk.factors.map(f => f.factor));
}
Search
Global search across all entities. Searches customers (via encrypted blind indexes), products, deals, and contracts.
Search across all resources. Minimum 2 characters.
| Parameter | Description |
| q required | Search query (min 2 characters) |
| limit | Max results (default: 10, max: 25) |
Activity Feed
Real-time event log and notification management. The activity feed records all significant events across deals, customers, payments, and more. Configure notification rules to route alerts to email, webhook, or in-app channels.
List activity feed events with optional filters.
| Parameter | Type | Description |
| event_type | string | Filter by event type (e.g. deal.created, payment.received) |
| actor_type | string | Filter by actor: user, agent, or system |
| entity_type | string | Filter by entity: deal, contract, customer |
| limit | integer | Max results (default: 50, max: 100) |
| offset | integer | Pagination offset |
Example
curl "https://api.salesbooth.com/v1/activity?event_type=deal.created&limit=20" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
List in-app notifications for the current user.
Example
curl "https://api.salesbooth.com/v1/activity?action=notifications" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
List notification rules. Rules define which events trigger notifications and where they are sent.
Example
curl "https://api.salesbooth.com/v1/activity?action=rules" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Create a notification rule.
| Field | Type | Description |
| event_type required | string | Event pattern to match (e.g. deal.signature_added, payment.*) |
| channel required | string | Delivery channel: email, webhook, or in_app |
| name | string | Rule display name |
Example
curl -X POST "https://api.salesbooth.com/v1/activity?action=create_rule" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"event_type": "deal.signature_added",
"channel": "email",
"name": "Notify on deal sign"
}'
Mark specific notifications as read. Use action=mark_all_read to mark all as read at once.
| Field | Type | Description |
| notification_ids required | array | Array of notification IDs to mark as read |
Example
curl -X POST "https://api.salesbooth.com/v1/activity?action=mark_read" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "notification_ids": ["notif_abc", "notif_def"] }'
Update an existing notification rule.
Example
curl -X PATCH "https://api.salesbooth.com/v1/activity?action=update_rule&rule_id=rule_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "channel": "webhook" }'
Delete a notification rule.
Example
curl -X DELETE "https://api.salesbooth.com/v1/activity?action=delete_rule&rule_id=rule_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Retrieve the current user’s activity notification preferences. Returns per-event-type channel settings (email, in-app, webhook).
Example
curl "https://api.salesbooth.com/v1/activity?action=preferences" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"deal.created": { "email": true, "in_app": true, "webhook": false },
"deal.signature_added": { "email": true, "in_app": true, "webhook": true },
"payment.received": { "email": true, "in_app": false, "webhook": true }
}
}
Save the current user’s activity notification preferences. Replaces all preferences for the authenticated user. Send the full preferences object keyed by event type.
Example
curl -X PUT "https://api.salesbooth.com/v1/activity?action=preferences" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"deal.created": { "email": true, "in_app": true, "webhook": false },
"deal.signature_added": { "email": true, "in_app": true, "webhook": true },
"payment.received": { "email": false, "in_app": true, "webhook": true }
}'
Batch Operations
Execute up to 25 API operations in a single request. All operations run inside a transaction — if any write fails, all mutations are rolled back. Ideal for reducing round-trips in integrations and complex workflows.
Transactional. All write operations in a batch are atomic. Any failure rolls back all mutations. Read operations (GET) are always included in the response regardless of write failures.
Execute multiple API operations in a single transactional request. Each operation specifies a method, resource, optional id, optional body, and optional version for optimistic locking.
| Field | Type | Description |
| operations required | array | Array of operation objects (max 25). Supported resources: deals, customers, products, contracts |
Example
curl -X POST https://api.salesbooth.com/v1/batch \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"operations": [
{ "method": "POST", "resource": "customers", "body": { "name": "Acme Corp" } },
{ "method": "POST", "resource": "deals", "body": { "title": "Enterprise Plan", "amount": 5000 } },
{ "method": "PATCH", "resource": "deals", "id": "deal_existing", "body": { "status": "active" }, "version": 3 }
]
}'
Response
{
"error": false,
"data": {
"results": [
{ "index": 0, "status": 201, "data": { "id": "cust_xxxxx" } },
{ "index": 1, "status": 201, "data": { "id": "deal_xxxxx" } },
{ "index": 2, "status": 200, "data": { "id": "deal_existing" } }
],
"committed": true
}
}
AI Agent Integration
Salesbooth provides first-class support for AI agents through tool schemas, MCP protocol, and an agent SDK. Agents can discover, negotiate, and execute deals automatically.
Tool Definitions
The /api/v1/tools endpoint returns curated tool definitions optimized for LLM function-calling. Each tool maps to a high-level business operation.
List agent tool definitions. Supports OpenAI, Anthropic, and universal formats.
| Parameter | Description |
| format | universal (default), openai, or anthropic |
| category | Filter: deal_management, product_catalog, customer_management, contracts, negotiation, templates, intelligence, payments, subscriptions, widgets, configuration, saved_configs, webhooks, delegations, compliance, search, audit, sandbox, workflows, agent_trust, federation, agent_registry, deal_participants, closure, catalog_management, documents, billing, headless_flow |
Example: OpenAI Function-Calling
curl https://api.salesbooth.com/v1/tools?format=openai \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Available Tools
| Tool | Category | Description |
discover_deals | Discovery | Find available deals matching criteria |
list_products | Discovery | Browse products and configurations |
get_deal_terms_schema | Discovery | Get the deal terms JSON Schema |
configure_product | Products | Validate a product configuration |
calculate_pricing | Products | Calculate pricing for a configuration |
create_deal | Deals | Create a new deal |
check_deal_status | Deals | Get deal state and line items |
update_deal | Deals | Update deal or transition status |
search_deals | Deals | Search deals by criteria |
negotiate_terms | Negotiation | Propose or counter-propose terms |
get_negotiation_history | Negotiation | View negotiation rounds |
accept_deal | Execution | Accept and close a deal |
sign_contract | Execution | Digitally sign deal terms |
MCP Server
The /api/v1/mcp endpoint implements the Model Context Protocol over HTTP using JSON-RPC 2.0.
MCP JSON-RPC endpoint. Supports initialize, tools/list, tools/call, tools/batch, resources/list, resources/read, resources/templates/list, resources/subscribe, resources/unsubscribe, prompts/list, prompts/get, and ping.
Example: MCP Initialize
curl -X POST https://api.salesbooth.com/v1/mcp \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"initialize","params":{}}'
Example: List MCP Tools
curl -X POST https://api.salesbooth.com/v1/mcp \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"2","method":"tools/list","params":{}}'
Agent SDK
The Agent SDK provides getToolDefinitions() and executeTool() for seamless LLM integration.
Node.js
const SalesboothAgent = require('./salesbooth-agent');
const agent = SalesboothAgent.init({
apiKey: 'sb_test_example_key_do_not_use',
delegationId: 'del_xxxxx' // optional
});
// Get tool definitions for OpenAI
const tools = agent.getToolDefinitions('openai');
// Execute a tool
const deals = await agent.executeTool('discover_deals', {
category: 'software',
max_price: 10000
});
Via the main SDK
const Salesbooth = require('salesbooth');
// Creates an agent client (requires salesbooth-agent.js)
const agent = Salesbooth.agent({
apiKey: 'sb_test_example_key_do_not_use',
delegationId: 'del_xxxxx'
});
const tools = agent.getToolDefinitions('anthropic');
Agent Scopes
| Scope | Description |
agent:discover | Discover deals, browse products, and read tool definitions |
agent:negotiate | Propose, counter, accept, or reject deal terms |
agent:execute | Create deals, sign contracts, and close deals |
agent:* | All agent scopes |
Delegation Tokens
Use delegation tokens to grant agents scoped access with spending limits. Pass the delegation ID via the X-Delegation-ID header.
Example: Agent with Delegation
curl https://api.salesbooth.com/v1/tools \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "X-Delegation-ID: del_xxxxx"
Agent Workflows
Autonomous deal orchestration. Agents can plan and execute multi-step deal workflows within delegation spending limits.
List agent workflows or retrieve a specific workflow with its execution history.
| Parameter | Type | Description |
| action | string | Query action: spending_summary, anomalies, agent_stats, pending_approvals, approval_status |
| id | string | Retrieve a specific workflow |
| status | string | Filter: planned, executing, negotiating, awaiting_approval, completed, failed, cancelled |
| delegation_id | string | Filter by delegation |
| limit | integer | Max results (default: 50) |
Example
curl https://api.salesbooth.com/v1/agent-workflow?status=executing \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Return agent spending analytics broken down by period.
| Parameter | Type | Description |
| period | string | Aggregation window: day, week, month (default: month) |
Example
curl "https://api.salesbooth.com/v1/agent-workflow?action=spending_summary&period=week" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Detect spending or behavioural anomalies across all agent workflows for this tenant. Also accepts action=detect_anomalies for SDK compatibility.
Example
curl "https://api.salesbooth.com/v1/agent-workflow?action=anomalies" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Return performance statistics for a specific agent key.
| Parameter | Type | Description |
| agent_id required | string | Agent key ID to retrieve statistics for |
| granularity | string | Time grouping: daily, weekly (default: daily) |
Example
curl "https://api.salesbooth.com/v1/agent-workflow?action=agent_stats&agent_id=key_xxxxx&granularity=weekly" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
List all workflows currently paused at an approval gate and awaiting a decision.
| Parameter | Type | Description |
| delegation_id | string | Filter by delegation |
| limit | integer | Max results (default: 50, max: 100) |
| offset | integer | Pagination offset (default: 0) |
Example
curl "https://api.salesbooth.com/v1/agent-workflow?action=pending_approvals" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Check the approval token status for a specific workflow — whether the one-time approval link has been used.
| Parameter | Type | Description |
| id required | string | Workflow ID to check |
Example
curl "https://api.salesbooth.com/v1/agent-workflow?action=approval_status&id=wf_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Plan a new workflow. The system generates a step-by-step execution plan based on the agent’s intent.
| Field | Type | Description |
| delegation_id required | string | Delegation providing spending limits |
| intent required | string | Natural language description of the workflow goal |
| constraints | object | Additional constraints (max_price, category, etc.) |
Example
curl -X POST https://api.salesbooth.com/v1/agent-workflow \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"delegation_id": "del_xxxxx",
"intent": "Find and negotiate the best enterprise software deal under $5000",
"constraints": { "max_price": 5000, "category": "software" }
}'
Execute a planned workflow. Runs each step in sequence, checking delegation limits at each stage.
Example
curl -X POST "https://api.salesbooth.com/v1/agent-workflow?id=wf_xxxxx&action=execute" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Modify a workflow’s associated deal while it is in progress.
| Field | Type | Description |
| (modifications) required | object | Key-value fields to update on the workflow’s deal (e.g. price, quantity) |
Example
curl -X POST "https://api.salesbooth.com/v1/agent-workflow?id=wf_xxxxx&action=modify" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "price": 4500, "quantity": 2 }'
Approve a workflow paused at an approval gate. Supports admin session approval and one-time token-based approval via webhook deep-links.
| Field / Parameter | Type | Description |
| token | string | One-time approval token (query param or body field) for token-based approval without a session |
| approved_by | string | Identifier of the approving party (body) |
| note | string | Optional approval note (body) |
Example
curl -X POST "https://api.salesbooth.com/v1/agent-workflow?id=wf_xxxxx&action=approve" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "note": "Approved after budget review" }'
Reject a workflow paused at an approval gate. Supports admin session rejection and one-time token-based rejection.
| Field / Parameter | Type | Description |
| token | string | One-time approval token (query param or body field) for token-based rejection without a session |
| rejected_by | string | Identifier of the rejecting party (body) |
| reason | string | Optional rejection reason (body) |
Example
curl -X POST "https://api.salesbooth.com/v1/agent-workflow?id=wf_xxxxx&action=reject" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "reason": "Deal value exceeds quarterly budget" }'
Resend the approval notification email and in-app alert for a workflow still awaiting a decision.
Example
curl -X POST "https://api.salesbooth.com/v1/agent-workflow?id=wf_xxxxx&action=resend_approval" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Escalate a pending approval request to the delegation grantor when the original reviewer is unresponsive.
| Field | Type | Description |
| escalation_reason required | string | Reason for escalation (max 2000 characters) |
Example
curl -X POST "https://api.salesbooth.com/v1/agent-workflow?id=wf_xxxxx&action=escalate_approval" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "escalation_reason": "Reviewer has not responded within 12 hours" }'
Approve a paused workflow using delegated authority — allows an agent key with the appropriate delegation to approve without an admin session.
| Field | Type | Description |
| delegation_id required | string | Delegation ID granting approval authority |
| approval_note | string | Optional note recorded with the approval (max 2000 characters) |
Example
curl -X POST "https://api.salesbooth.com/v1/agent-workflow?id=wf_xxxxx&action=delegate_approve" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "delegation_id": "del_xxxxx", "approval_note": "Within authorised spend limit" }'
Cancel a workflow in progress.
Example
curl -X POST "https://api.salesbooth.com/v1/agent-workflow?id=wf_xxxxx&action=cancel" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Agent Trust
Per-API-key trust scoring, capability gating, and abuse protection. Agent trust levels determine transaction caps, allowed actions, and metered spending limits.
Who needs this: Agent Trust is relevant if you are building or integrating with autonomous AI agents that create or execute deals on behalf of users. Trust levels unlock higher transaction caps and advanced capabilities (delegation, federation) as an agent demonstrates a track record of reliable behaviour.
When to skip this: For standard server-side integrations using your own API key (not an agent key), trust levels do not apply. Human-driven integrations are not subject to trust caps.
Prerequisite: An agent API key (created with agent_key: true). Regular API keys are not subject to the trust tier system.
Trust Level Reference
| Level | Label | Transaction Cap | Capabilities | How to Reach |
0 |
Untrusted |
$0 — no transactions |
Read-only discovery |
Default for new API keys |
1 |
Provisional |
$500 per deal |
Create deals, propose negotiations |
Score ≥ 20 — complete 1 deal |
2 |
Established |
$5,000 per deal |
Full deal management, delegation |
Score ≥ 50 — complete 5 deals |
3 |
Trusted |
Unlimited |
All capabilities, federation |
Score ≥ 80 — 30-day track record |
4 |
Verified Partner |
Unlimited |
All + system-level tools |
Manual promotion by tenant admin |
Trust Cap Exception: Attempting a deal above your transaction cap returns 403 trust_cap_exceeded. The response includes details.transaction_cap (your current limit) and details.attempted_amount. Complete more deals successfully to earn a higher trust level.
Get the current agent’s trust level, score, capabilities, and progress towards the next level.
| Parameter | Type | Description |
| action | string | history for trust level change log, locks for active capability locks |
| limit | integer | Max results for history (default: 50) |
Example
curl https://api.salesbooth.com/v1/agent-trust \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"key_id": "key_abc123",
"trust_level": 2,
"trust_label": "Established",
"score": 62,
"transaction_cap": 5000,
"capabilities": ["deal_management", "negotiation", "templates", "intelligence"],
"locked_capabilities": [],
"next_level": { "level": 3, "label": "Trusted", "score_needed": 80 },
"statistics": {
"deals_completed": 7,
"deals_failed": 0,
"total_deal_value": 14350.00
}
}
}
Retrieve the trust level change history for the authenticated API key.
Example
curl "https://api.salesbooth.com/v1/agent-trust?action=history&limit=10" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Verifiable Credentials
Agents can receive verifiable W3C credentials attesting to their trust level and completed deal history. Credentials can be presented to third-party tenants during federation to establish cross-tenant trust without starting from level 0.
Issue a verifiable credential for the authenticated agent’s current trust level and statistics. The credential is signed with the tenant’s Ed25519 key and can be presented to other tenants.
Example
curl -X POST https://api.salesbooth.com/v1/agent-trust-credentials \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "credential_type": "TrustLevelCredential" }'
Response
{
"error": false,
"data": {
"credential_id": "cred_xyz789",
"type": "TrustLevelCredential",
"trust_level": 2,
"issued_at": "2026-03-12T10:00:00Z",
"expires_at": "2026-09-12T10:00:00Z",
"jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9..."
}
}
List verifiable credentials issued to the authenticated agent.
Example
curl https://api.salesbooth.com/v1/agent-trust-credentials \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Trust-Related Webhook Events
| agent.trust.level_changed | Trust level promoted or demoted |
| agent.trust_cap_exceeded | Agent attempted a deal above their trust cap |
| agent.trust.abuse_detected | Anomalous behaviour detected — capability lock applied |
| agent.trust.credential_issued | Verifiable credential issued to agent |
| agent.trust.credential_revoked | Previously issued credential revoked |
MCP Protocol
Salesbooth implements the Model Context Protocol (MCP) over HTTP using JSON-RPC 2.0. The MCP endpoint exposes 192 tools across 28 categories, resource browsing, prompt templates, and subscriptions — giving AI agents a structured, discoverable interface to the full Salesbooth platform.
Endpoint: POST https://api.salesbooth.com/v1/mcp
Protocol Version: 2024-11-05 — Server: salesbooth-mcp v2.0
Required scope: agent:discover (to connect). Individual tools require additional scopes — see the Scope Requirements table below.
1. Connection & Initialize Handshake
All MCP communication uses POST /api/v1/mcp with a JSON-RPC 2.0 body. Authenticate with your API key in the Authorization header. Begin every session with an initialize request to confirm capabilities.
MCP JSON-RPC 2.0 transport. All methods use this single endpoint. Supports initialize, tools/list, tools/call, tools/batch, resources/list, resources/templates/list, resources/read, resources/subscribe, resources/unsubscribe, notifications/list, prompts/list, prompts/get, and ping.
| Header | Description |
| Authorization | Bearer <api_key> — required. Use an API key with at minimum agent:discover scope. |
| X-Delegation-ID | Optional delegation token ID to execute tools under a scoped delegation with spending limits. |
| Content-Type | application/json |
Initialize request
curl -X POST https://api.salesbooth.com/v1/mcp \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "initialize",
"params": {}
}'
Initialize response
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": { "listChanged": false, "batch": true },
"resources": { "subscribe": true, "listChanged": false },
"prompts": { "listChanged": false }
},
"serverInfo": {
"name": "salesbooth-mcp",
"version": "2.0"
}
}
}
2. Tool Discovery — tools/list
Retrieve the full catalogue of 192 agent tools. Each tool includes a JSON Schema for its parameters, making it directly consumable by LLM function-calling APIs (OpenAI, Anthropic, etc.).
Request
curl -X POST https://api.salesbooth.com/v1/mcp \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "2",
"method": "tools/list",
"params": {}
}'
Response (excerpt — one tool shown)
{
"jsonrpc": "2.0",
"id": "2",
"result": {
"tools": [
{
"name": "discover_deals",
"description": "Find available deals matching criteria. Returns deals that can be negotiated or accepted. Use this as the first step to find deals for a customer.",
"inputSchema": {
"type": "object",
"properties": {
"category": { "type": "string", "description": "Filter by product category" },
"min_price": { "type": "number" },
"max_price": { "type": "number" },
"currency": { "type": "string", "pattern": "^[A-Z]{3}$" },
"pricing_model": {
"type": "string",
"enum": ["one_time", "recurring", "usage_based", "tiered"]
},
"limit": { "type": "integer", "minimum": 1, "maximum": 100 }
},
"required": [],
"additionalProperties": false
}
}
// ... 155 more tools
]
}
}
Tool Categories
| Category | Description |
deal_management | Create, update, and manage deals through their full lifecycle |
product_catalog | Browse, configure, and manage products and pricing |
customer_management | Create and manage customer records |
contracts | Create, sign, activate, and manage contracts |
negotiation | Propose, counter, and resolve deal negotiations |
templates | Create, clone, and instantiate deal templates |
intelligence | AI-powered deal scoring, pricing analytics, and pipeline insights |
payments | Process payments, refunds, and manual payment recordings |
subscriptions | Manage recurring billing subscriptions |
widgets | Configure and manage embeddable deal widgets |
configuration | Manage product families, option groups, and pricing rules |
saved_configs | Save, share, and convert product configurations to deals |
webhooks | Manage webhook endpoints and event delivery |
delegations | Create and manage agent delegation permissions |
compliance | GDPR operations and audit trail exports |
search | Global search across customers, products, deals, and contracts |
audit | View and verify audit trails for entities |
sandbox | Test environment setup, seeding, and webhook simulation |
workflows | Autonomous deal orchestration with delegation-scoped execution |
agent_trust | Check trust level, capabilities, and trust lock status for the current agent |
federation | Discover offerings on remote Salesbooth instances and negotiate cross-instance deals |
3. Tool Execution — tools/call
Call any tool by name with its parameters. The server validates your scope, executes the tool, and returns structured JSON content. If a tool fails, isError is true and the content describes the error.
Request format
{
"jsonrpc": "2.0",
"id": "<request_id>",
"method": "tools/call",
"params": {
"name": "<tool_name>",
"arguments": { /* tool parameters */ }
}
}
Success response format
{
"jsonrpc": "2.0",
"id": "<request_id>",
"result": {
"content": [
{ "type": "text", "text": "<JSON string of tool result>" }
],
"isError": false
}
}
Workflow 1: Create a Deal from Products
Discover a customer → create a deal → add line items → transition to in_progress.
Step 1: Find the customer
{
"jsonrpc": "2.0", "id": "w1a", "method": "tools/call",
"params": {
"name": "list_customers",
"arguments": { "search": "Acme Corp", "limit": 5 }
}
}
Step 2: Create the deal (scope: deals:write)
{
"jsonrpc": "2.0", "id": "w1b", "method": "tools/call",
"params": {
"name": "create_deal",
"arguments": {
"customer_id": "cust_abc123",
"currency": "USD",
"deal_type": "one_time",
"description": "Enterprise software package"
}
}
}
Step 3: Add a line item (scope: deals:write)
{
"jsonrpc": "2.0", "id": "w1c", "method": "tools/call",
"params": {
"name": "add_deal_item",
"arguments": {
"id": "deal_xyz789",
"product_id": "prod_platform_pro",
"quantity": 10,
"unit_price": 99.00
}
}
}
Step 4: Transition to in_progress (scope: deals:write)
{
"jsonrpc": "2.0", "id": "w1d", "method": "tools/call",
"params": {
"name": "transition_deal",
"arguments": { "id": "deal_xyz789", "status": "in_progress" }
}
}
Workflow 2: Score a Deal and Get Recommendations
Use intelligence tools to score deal health and fetch pricing recommendations.
Score the deal (scope: intelligence:read)
{
"jsonrpc": "2.0", "id": "w2a", "method": "tools/call",
"params": {
"name": "score_deal",
"arguments": { "deal_id": "deal_xyz789" }
}
}
Get pricing recommendations (scope: intelligence:read)
{
"jsonrpc": "2.0", "id": "w2b", "method": "tools/call",
"params": {
"name": "get_pricing_suggestion",
"arguments": { "deal_id": "deal_xyz789" }
}
}
Response excerpt
{
"jsonrpc": "2.0", "id": "w2b",
"result": {
"content": [{
"type": "text",
"text": "{\"score\":82,\"confidence\":\"high\",\"recommendations\":[{\"type\":\"discount\",\"amount\":5,\"rationale\":\"Volume threshold reached\"}]}"
}],
"isError": false
}
}
Workflow 3: Negotiate Terms with a Counter-Proposal
Submit a proposal, retrieve the negotiation history, then counter. Requires agent:negotiate scope.
Submit a proposal (scope: agent:negotiate)
{
"jsonrpc": "2.0", "id": "w3a", "method": "tools/call",
"params": {
"name": "negotiate_terms",
"arguments": {
"deal_id": "deal_xyz789",
"action": "propose",
"terms": { "discount_percent": 10, "payment_terms": "net_30" }
}
}
}
Get negotiation history (scope: deals:read)
{
"jsonrpc": "2.0", "id": "w3b", "method": "tools/call",
"params": {
"name": "get_negotiation_history",
"arguments": { "deal_id": "deal_xyz789" }
}
}
Send counter-proposal (scope: agent:negotiate)
{
"jsonrpc": "2.0", "id": "w3c", "method": "tools/call",
"params": {
"name": "suggest_counter_terms",
"arguments": {
"deal_id": "deal_xyz789",
"negotiation_id": "neg_abc456",
"current_terms": { "discount_percent": 7, "payment_terms": "net_15" }
}
}
}
Workflow 4: Check Delegation Spending Limits
Before executing an expensive action, verify the active delegation has sufficient spending capacity.
Read delegation scope (scope: delegations:read)
{
"jsonrpc": "2.0", "id": "w4a", "method": "tools/call",
"params": {
"name": "get_delegation",
"arguments": { "id": "del_xxxxx" }
}
}
Response
{
"jsonrpc": "2.0", "id": "w4a",
"result": {
"content": [{
"type": "text",
"text": "{\"id\":\"del_xxxxx\",\"allowed_actions\":[\"deals:write\",\"agent:negotiate\"],\"spending_limits\":{\"max_transaction_amount\":5000.00,\"max_daily_amount\":10000.00},\"expires_at\":\"2026-12-31T23:59:59Z\"}"
}],
"isError": false
}
}
Workflow 5: Search Across All Entities
Use the global search tool to find customers, products, deals, or contracts by keyword. Requires agent:discover scope.
Global search (scope: agent:discover)
{
"jsonrpc": "2.0", "id": "w5", "method": "tools/call",
"params": {
"name": "global_search",
"arguments": {
"query": "enterprise",
"types": ["deals", "customers", "products"],
"limit": 10
}
}
}
Response
{
"jsonrpc": "2.0", "id": "w5",
"result": {
"content": [{
"type": "text",
"text": "{\"results\":[{\"type\":\"deal\",\"id\":\"deal_xyz789\",\"label\":\"Enterprise Software Package\",\"score\":0.97},{\"type\":\"product\",\"id\":\"prod_platform_pro\",\"label\":\"Platform Pro (Enterprise)\",\"score\":0.91}],\"total\":12}"
}],
"isError": false
}
}
4. Resource Browsing
Resources give agents read access to live tenant data as structured documents. Salesbooth provides static resources (schemas, documentation) and dynamic resources (live deal, product, and customer data).
List all resources — resources/list
Request
{
"jsonrpc": "2.0", "id": "r1",
"method": "resources/list",
"params": {}
}
Response (resource URIs)
{
"jsonrpc": "2.0", "id": "r1",
"result": {
"resources": [
{ "uri": "salesbooth://schemas/deal-terms", "name": "Deal Terms Schema", "mimeType": "application/schema+json" },
{ "uri": "salesbooth://schemas/state-machine", "name": "Deal State Machine", "mimeType": "application/json" },
{ "uri": "salesbooth://docs/tools", "name": "Agent Tool Reference", "mimeType": "text/plain" },
{ "uri": "salesbooth://deals", "name": "Active Deals", "mimeType": "application/json" },
{ "uri": "salesbooth://products", "name": "Product Catalog", "mimeType": "application/json" },
{ "uri": "salesbooth://customers", "name": "Customer Directory", "mimeType": "application/json" },
{ "uri": "salesbooth://widgets", "name": "Widget Configurations", "mimeType": "application/json" },
{ "uri": "salesbooth://intelligence/pipeline", "name": "Pipeline Analytics", "mimeType": "application/json" },
{ "uri": "salesbooth://delegations", "name": "Agent Delegations", "mimeType": "application/json" },
{ "uri": "salesbooth://contracts", "name": "Contracts", "mimeType": "application/json" },
{ "uri": "salesbooth://templates", "name": "Deal Templates", "mimeType": "application/json" },
{ "uri": "salesbooth://saved-configs", "name": "Saved Configurations", "mimeType": "application/json" },
{ "uri": "salesbooth://subscriptions", "name": "Subscriptions", "mimeType": "application/json" },
{ "uri": "salesbooth://webhooks", "name": "Webhook Endpoints", "mimeType": "application/json" }
]
}
}
Read a resource — resources/read
Request
{
"jsonrpc": "2.0", "id": "r2",
"method": "resources/read",
"params": { "uri": "salesbooth://deals" }
}
Response
{
"jsonrpc": "2.0", "id": "r2",
"result": {
"contents": [{
"uri": "salesbooth://deals",
"mimeType": "application/json",
"text": "{\"deals\":[{\"id\":\"deal_xyz789\",\"status\":\"in_progress\",\"total_amount\":\"990.00\",\"currency\":\"USD\",\"customer_id\":\"cust_abc123\"}],\"pagination\":{\"total\":42,\"limit\":20,\"offset\":0}}"
}]
}
}
Dynamic resource templates — resources/templates/list
Resource templates allow reading a single entity by ID using parameterized URIs.
Request
{
"jsonrpc": "2.0", "id": "r3",
"method": "resources/templates/list",
"params": {}
}
Response (excerpt)
{
"jsonrpc": "2.0", "id": "r3",
"result": {
"resourceTemplates": [
{ "uriTemplate": "salesbooth://deals/{deal_id}", "name": "Deal by ID", "mimeType": "application/json" },
{ "uriTemplate": "salesbooth://products/{product_id}", "name": "Product by ID", "mimeType": "application/json" },
{ "uriTemplate": "salesbooth://customers/{customer_id}", "name": "Customer by ID", "mimeType": "application/json" },
{ "uriTemplate": "salesbooth://contracts/{contract_id}", "name": "Contract by ID", "mimeType": "application/json" }
]
}
}
Read a single deal by ID
{
"jsonrpc": "2.0", "id": "r4",
"method": "resources/read",
"params": { "uri": "salesbooth://deals/deal_xyz789" }
}
5. Prompt Templates
Prompt templates are guided multi-step workflows. Agents can inject them as system/user messages to guide an LLM through complex operations without needing to know every individual tool call.
List prompts — prompts/list
Request
{
"jsonrpc": "2.0", "id": "p1",
"method": "prompts/list",
"params": {}
}
Response
{
"jsonrpc": "2.0", "id": "p1",
"result": {
"prompts": [
{ "name": "create-deal", "description": "Guided deal creation workflow: select products, look up or create a customer, configure pricing, and submit the deal." },
{ "name": "negotiate-deal", "description": "Structured negotiation workflow: review current deal terms, apply intelligence scoring, propose or counter terms." },
{ "name": "configure-widget", "description": "Widget setup workflow: select a site, choose products, configure theme and steps, generate embed code." },
{ "name": "review-pipeline", "description": "Pipeline health check: analyze deal distribution by status, identify bottlenecks, get recommended actions." },
{ "name": "manage-delegation", "description": "Create or update agent delegations: define scope, spending limits, and expiry for sub-agents." }
]
}
}
Get a prompt — prompts/get
Request
{
"jsonrpc": "2.0", "id": "p2",
"method": "prompts/get",
"params": {
"name": "negotiate-deal",
"arguments": {
"deal_id": "deal_xyz789",
"strategy": "balanced"
}
}
}
Response
{
"jsonrpc": "2.0", "id": "p2",
"result": {
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "You are a deal negotiation agent for Salesbooth. Your task:\n1. Retrieve the current state of deal deal_xyz789 using check_deal_status.\n2. Score the deal using score_deal to understand its health and value.\n3. Review negotiation history via get_negotiation_history.\n4. Apply a balanced strategy: aim for fair value on both sides.\n5. Submit a counter-proposal or accept terms using negotiate_terms / suggest_counter_terms.\nAlways verify scope before acting. Stop if spending limits are exceeded."
}
}
]
}
}
6. Error Handling
MCP errors follow the JSON-RPC 2.0 error object format. Tool execution errors are returned as isError: true in the result (not as JSON-RPC errors) so the agent can continue the session.
| Error Code | Meaning | Recovery |
-32600 |
Invalid Request — missing jsonrpc, method, or invalid envelope structure |
Check your request body includes "jsonrpc": "2.0" and a valid method string |
-32601 |
Method Not Found — the MCP method name is unknown |
Verify the method is one of the supported methods listed above. Check spelling. |
-32602 |
Invalid Params — missing required tool parameter or wrong type |
Call tools/list to inspect the tool’s inputSchema and ensure all required parameters are present |
-32603 |
Internal Error — unexpected server-side error |
Retry once after a short delay. If persistent, check the sandbox environment or contact support. |
Example JSON-RPC error response
{
"jsonrpc": "2.0",
"id": "3",
"error": {
"code": -32602,
"message": "Missing required parameter: name"
}
}
Tool-level error (isError: true in result)
{
"jsonrpc": "2.0",
"id": "4",
"result": {
"content": [{
"type": "text",
"text": "{\"error\":true,\"code\":\"insufficient_scope\",\"message\":\"Tool 'create_deal' requires scope 'deals:write'\"}"
}],
"isError": true
}
}
7. Scope Requirements by Category
Each MCP tool requires one or more scopes. The base connection itself requires agent:discover. Grant additional scopes by creating an API key with the scopes your agent needs (see Scopes & Permissions).
| Category | Required Scopes |
| Deal Management | agent:discover, deals:read, deals:write, agent:execute |
| Product Catalog | products:read, products:write |
| Customer Management | customers:read, customers:write |
| Contracts | contracts:read, contracts:write |
| Negotiation | agent:negotiate |
| Deal Templates | deals:read, deals:write |
| Intelligence | deals:read, intelligence:read, intelligence:write |
| Payments | deals:read, deals:write |
| Subscriptions | deals:read, deals:write |
| Widgets | products:read, products:write, deals:read, deals:write |
| Product Configuration | products:read, products:write |
| Saved Configurations | deals:read, deals:write |
| Webhooks | webhooks:read, webhooks:write |
| Delegations | delegations:read, delegations:write |
| Compliance | audit:export, customers:read, customers:write |
| Search | agent:discover |
| Audit | audit:read |
| Sandbox | sandbox:read, sandbox:write |
| Agent Workflows | agent:execute |
| Agent Trust | agent:discover |
| Cross-Instance Federation | agent:discover, agent:negotiate, agent:execute |
| Agent Registry | agent:discover |
| Deal Participants | deals:read, deals:write |
| Deal Closure | deals:read, deals:write, agent:execute |
| Catalog Management | products:write |
| Documents | deals:read, deals:write, customers:read |
| Billing | billing:read |
8. Circuit Breaker & Retry Guidance
Tool execution is wrapped in a circuit breaker with a 10-second request timeout and a failure threshold of 5 consecutive failures within 60 seconds. If the circuit is open, the MCP server returns a service_unavailable error with retryable: true in the content.
| Parameter | Value | Meaning |
| Request timeout | 10 seconds | Individual tool call must complete within 10 s or it fails |
| Failure threshold | 5 failures | Circuit opens after 5 consecutive failures in the window |
| Failure window | 60 seconds | Failures older than 60 s are no longer counted |
| Recovery timeout | 30 seconds | Circuit moves to half-open after 30 s; one probe request is allowed |
Circuit breaker open — retryable error in tool result
{
"jsonrpc": "2.0", "id": "5",
"result": {
"content": [{
"type": "text",
"text": "{\"error\":true,\"code\":\"service_unavailable\",\"message\":\"Tool execution temporarily unavailable (circuit breaker open). Retry after a short delay.\",\"retryable\":true}"
}],
"isError": true
}
}
When retryable is true, wait at least 30 seconds before retrying. Do not flood the endpoint — exponential backoff is recommended. A 503 HTTP response (rather than a JSON-RPC error) means the MCP server itself is unreachable; apply the same backoff strategy.
9. Cross-Instance Federation
The federation tool category implements the salesbooth-negotiate/1.0 protocol, allowing agents to discover offerings on remote Salesbooth instances and execute cross-instance deals without leaving the MCP session.
Discover remote offerings (scope: agent:discover)
{
"jsonrpc": "2.0", "id": "f1", "method": "tools/call",
"params": {
"name": "cross_instance_discover",
"arguments": { "instance": "partner.salesbooth.com" }
}
}
Initiate a cross-instance negotiation (scope: agent:negotiate)
{
"jsonrpc": "2.0", "id": "f2", "method": "tools/call",
"params": {
"name": "cross_instance_negotiate",
"arguments": {
"target_instance": "partner.salesbooth.com",
"type": "propose",
"payload": { "deal_id": "deal_xyz789", "proposed_terms": { "discount_percent": 5 } }
}
}
}
Federation requests are authenticated end-to-end using tenant key pairs and signed JWT assertions. The remote instance validates the incoming salesbooth-negotiate/1.0 request against its federation discovery endpoint (/.well-known/salesbooth-federation) before accepting any proposal.
Cross-Instance Federation
The Federation API enables agents and tenants to discover offerings on remote Salesbooth instances and execute cross-instance deals using the salesbooth-negotiate/1.0 protocol. Federation is generally available — no preview flag is required.
Endpoint: POST /api/v1/federation/negotiate • GET /api/v1/federation/negotiate
Required scopes: agent:discover (GET), agent:negotiate (POST)
Authentication: Requests are signed end-to-end with tenant Ed25519 key pairs. Remote instances validate incoming envelopes against the originator’s DID document at /.well-known/salesbooth-federation.
Actions (POST)
| Action | Description |
discover | Cross-instance product and deal discovery — find offerings available on a remote instance |
send | Send a signed negotiation envelope to a remote instance to initiate a deal |
negotiate | Receive and process an incoming negotiation envelope from a remote instance |
escrow | Coordinate matched escrow creation across both instances simultaneously |
settle | Initiate 2-phase escrow settlement (PREPARE → COMMIT or ROLLBACK) |
dispute | Initiate escrow dispute — freezes funds on both sides and fires escrow.* webhooks |
GET Actions
| ?action= | Description |
status (default) | Return this instance’s federation capabilities manifest (protocol version, supported actions, public key) |
audit | Retrieve the federation audit trail for a cross-instance transaction by ?xref_id= |
Get federation status
curl https://api.salesbooth.com/v1/federation/negotiate \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Discover remote offerings
curl -X POST https://api.salesbooth.com/v1/federation/negotiate \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"action": "discover",
"remote_url": "https://partner.salesbooth.com",
"query": { "category": "software", "currency": "USD" }
}'
Send a negotiation envelope
curl -X POST https://api.salesbooth.com/v1/federation/negotiate \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"action": "send",
"remote_url": "https://partner.salesbooth.com",
"envelope": {
"deal_id": "deal_remote_123",
"proposed_terms": { "discount_percent": 10, "currency": "USD" },
"expires_at": "2026-03-13T12:00:00Z"
}
}'
Return this instance’s federation capabilities manifest or retrieve the audit trail for a specific cross-instance transaction. Requires agent:discover scope.
| Parameter | Type | Description |
| action | string | status (default) for capabilities manifest; audit to retrieve a transaction audit trail |
| xref_id | string | Cross-reference transaction ID — required when action=audit |
Example — get federation status
curl https://api.salesbooth.com/v1/federation/negotiate \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Example — retrieve audit trail
curl "https://api.salesbooth.com/v1/federation/negotiate?action=audit&xref_id=xref_abc123" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Process a cross-instance negotiation action: discover remote offerings, send or receive negotiation envelopes, coordinate escrow, settle, or raise disputes. Requires agent:negotiate scope.
| Field | Type | Description |
| action required | string | discover, send, negotiate, escrow, settle, or dispute |
| remote_url | string | Base URL of the remote Salesbooth instance (required for discover and send) |
| envelope | object | Signed negotiation envelope (required for send and negotiate) |
| query | object | Discovery query filters (used with action=discover): category, currency, etc. |
Example — discover remote offerings
curl -X POST https://api.salesbooth.com/v1/federation/negotiate \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"action": "discover",
"remote_url": "https://partner.salesbooth.com",
"query": { "category": "software", "currency": "USD" }
}'
Instance Discovery
Remote instances advertise their federation support via a well-known endpoint. This is used during the handshake to verify the remote tenant’s public key and supported protocol versions.
Well-known discovery endpoint
GET /.well-known/salesbooth-federation
Return the federation discovery manifest for a specific tenant. Public endpoint — no authentication required. Remote instances call this to retrieve the tenant’s federation capabilities, supported protocol versions, and public Ed25519 key before initiating a cross-instance negotiation.
| Parameter | Type | Description |
| tenant_id required | string | Tenant whose federation manifest to retrieve |
Example
curl "https://api.salesbooth.com/v1/federation/discovery?tenant_id=tenant_xxxxx"
Response
{
"error": false,
"success": true,
"data": {
"manifest": {
"version": "1.0",
"tenant_id": "tenant_xxxxx",
"endpoints": {
"negotiate": "https://api.salesbooth.com/v1/federation/negotiate",
"did_document": "https://api.salesbooth.com/v1/did-document"
},
"capabilities": ["negotiate", "escrow", "settle", "dispute"],
"protocol_versions": ["salesbooth-negotiate/1.0"]
}
}
}
Get a tenant’s Ed25519 public key. Public endpoint — no authentication required. Used by third parties and remote instances to fetch a tenant’s signing key for independent verification of deal signatures without trusting Salesbooth infrastructure. Returns the key in raw (base64), PEM, and JWK formats by default.
| Parameter | Type | Description |
| tenant_id | string | Tenant whose public key to retrieve (required if key_id not provided). Pass _current to resolve from session. |
| key_id | string | Retrieve a specific signing key by ID (useful when verifying a signature that references a rotated key) |
| format | string | Key format: raw, pem, jwk, or all (default) |
| include_rotated | flag | Return all keys including rotated ones (omit for active key only) |
Example
curl "https://api.salesbooth.com/v1/tenant/public-key?tenant_id=tenant_xxxxx"
Response
{
"error": false,
"data": {
"tenant_id": "tenant_xxxxx",
"key_id": "key_abc123",
"algorithm": "ed25519",
"key_version": 1,
"status": "active",
"created_at": "2026-01-15T08:00:00Z",
"public_key": "MCowBQYDK2VwAyEA...",
"public_key_pem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA...\n-----END PUBLIC KEY-----",
"public_key_jwk": {
"kty": "OKP",
"crv": "Ed25519",
"kid": "key_abc123",
"x": "..."
}
}
}
Trust requirement: Agents must be at Trust Level 3 (Trusted) to access federation capabilities. Cross-instance negotiation envelopes include a verifiable credential attesting to the originating agent’s trust level, which the remote instance validates before accepting any proposal.
DID Document
Every Salesbooth tenant publishes a W3C Decentralized Identifier (DID) document that remote instances use to verify deal signatures and federation credentials without trusting Salesbooth infrastructure.
Return the W3C DID document for a tenant. Public endpoint — no authentication required. Includes the tenant’s Ed25519 verification method and service endpoints for federation, deal verification, and key rotation.
| Parameter | Type | Description |
| tenant_id | string | Tenant whose DID document to retrieve. Omit to retrieve the document for the authenticated tenant. |
Example
curl "https://api.salesbooth.com/v1/did-document?tenant_id=tenant_xxxxx"
Response
{
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:web:salesbooth.com:tenant_xxxxx",
"verificationMethod": [
{
"id": "did:web:salesbooth.com:tenant_xxxxx#key-1",
"type": "Ed25519VerificationKey2020",
"controller": "did:web:salesbooth.com:tenant_xxxxx",
"publicKeyMultibase": "z..."
}
],
"authentication": ["did:web:salesbooth.com:tenant_xxxxx#key-1"],
"service": [
{
"id": "did:web:salesbooth.com:tenant_xxxxx#federation",
"type": "SalesboothFederation",
"serviceEndpoint": "https://api.salesbooth.com/v1/federation/negotiate"
}
]
}
Federation Peers
Manage the list of trusted remote Salesbooth instances your tenant federates with. Peers are used by the federation engine to pre-authorise cross-instance deal discovery and negotiation without requiring per-request trust verification. Requires agent:execute scope.
List all federation peers for the tenant. Requires agent:discover scope.
Example
curl https://api.salesbooth.com/v1/federation-peers \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"peers": [
{
"id": 1,
"hostname": "partner.salesbooth.com",
"remote_tenant_id": "tenant_yyyyy",
"trust_level": 3,
"status": "active",
"created_at": "2026-01-15T10:00:00Z"
}
],
"count": 1,
"open_mode": false
}
}
Register a new federation peer. Requires agent:execute scope.
| Field | Type | Description |
| hostname required | string | Hostname of the remote Salesbooth instance (e.g. partner.salesbooth.com) |
| remote_tenant_id | string | Tenant ID on the remote instance to federate with specifically |
| trust_level | integer | Initial trust level for this peer (0–5, default: 1) |
| status | string | active or suspended (default: active) |
Example
curl -X POST https://api.salesbooth.com/v1/federation-peers \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"hostname": "partner.salesbooth.com",
"remote_tenant_id": "tenant_yyyyy",
"trust_level": 3
}'
Response (201)
{
"error": false,
"data": {
"id": 1,
"hostname": "partner.salesbooth.com",
"remote_tenant_id": "tenant_yyyyy",
"trust_level": 3,
"status": "active"
}
}
Update a federation peer’s trust level or status. Requires agent:execute scope.
| Field | Type | Description |
| status | string | active or suspended |
| trust_level | integer | New trust level (0–5) |
Example
curl -X PATCH "https://api.salesbooth.com/v1/federation-peers?id=1" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "status": "suspended" }'
Response
{ "error": false, "data": { "updated": true, "id": 1 } }
Remove a federation peer. Cross-instance negotiations with this peer will no longer be pre-authorised. Requires agent:execute scope.
Example
curl -X DELETE "https://api.salesbooth.com/v1/federation-peers?id=1" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{ "error": false, "data": { "deleted": true, "id": 1 } }
API Keys
Create and manage API keys for your integration. Keys carry scopes that restrict which operations they can perform. This endpoint requires session (cookie) authentication — API keys cannot be used to manage other API keys.
Session authentication required. All /api/v1/keys endpoints require an active dashboard session. You cannot use an API key to create or revoke other API keys.
List all API keys for your tenant. Secret values are masked after initial creation.
Response
{
"error": false,
"data": [
{
"id": "key_xxxxx",
"name": "Production Integration",
"prefix": "sb_live_",
"scopes": ["deals:read", "customers:read"],
"created_at": "2026-01-15T10:00:00Z",
"last_used_at": "2026-03-10T08:30:00Z"
}
]
}
Create a new API key. The full secret is only returned once at creation time — store it securely.
| Field | Type | Description |
| name required | string | Descriptive name for the key |
| scopes | array | Array of scope strings (see Scopes & Permissions). Defaults to full access (["*"]) if omitted. |
| environment | string | live or test (default: live) |
| expires_at | string | ISO 8601 expiry datetime (optional) |
Example
curl -X POST https://api.salesbooth.com/v1/keys \
-H "Cookie: session=..." \
-H "Content-Type: application/json" \
-d '{
"name": "CI/CD Pipeline",
"scopes": ["deals:read", "customers:write"],
"environment": "test"
}'
Response (201)
{
"error": false,
"data": {
"id": "key_xxxxx",
"secret": "sb_test_xxxxxxxxxxxxxxxxxxxxxxxx",
"name": "CI/CD Pipeline",
"scopes": ["deals:read", "customers:write"]
}
}
Update an API key’s name, scopes, or expiry date.
Example
curl -X PATCH "https://api.salesbooth.com/v1/keys?id=key_xxxxx" \
-H "Cookie: session=..." \
-H "Content-Type: application/json" \
-d '{ "name": "Updated Key", "scopes": ["deals:read", "deals:write"] }'
Revoke an API key immediately. All requests using this key will be rejected with 401 INVALID_KEY.
Example
curl -X DELETE "https://api.salesbooth.com/v1/keys?id=key_xxxxx" \
-H "Cookie: session=..."
Sandbox
Test your integration without affecting live data. Sandbox endpoints require a test API key (sb_test_*) or sandbox mode enabled in the dashboard. All sandbox data is isolated from production.
Test keys only. All sandbox endpoints return 403 SANDBOX_ONLY when called with a live API key (sb_live_*). Generate a test key from the API Keys page in your dashboard.
Clear all test data for your tenant. Deletes test deals, customers, products, contracts, and escrow records in dependency-safe order. Live data is never affected.
Example
curl -X POST https://api.salesbooth.com/v1/sandbox/reset \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"action": "reset",
"environment": "test",
"sandbox": true,
"deleted": {
"deals": 10,
"customers": 5,
"products": 10,
"contracts": 1
},
"total_deleted": 26,
"message": "Cleared 26 test records across 4 tables."
}
}
Populate your sandbox with representative test data. Creates 5 customers, 10 products (subscriptions and one-time), 10 deals across all pipeline stages (draft, in_progress, pending_signature, pending_payment, closed, cancelled), deal line items, and 1 contract.
Example
curl -X POST https://api.salesbooth.com/v1/sandbox/seed \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response (201)
{
"error": false,
"data": {
"action": "seed",
"environment": "test",
"sandbox": true,
"seeded": {
"customers": 5,
"products": 10,
"deals": 10,
"deal_line_items": 22,
"contracts": 1
},
"total_seeded": 48,
"message": "Created 48 test records: 5 customers, 10 products, 10 deals, 22 line items, 1 contracts."
}
}
Trigger a webhook event with a synthetic payload. The event is dispatched through the normal webhook system to all active webhooks subscribed to the specified event type. Use this to test your webhook handlers without creating real data.
| Field | Description |
| event required | Event type to simulate (e.g. deal.created, deal.closed, payment.received) |
| data | Custom payload object. If omitted, a realistic synthetic payload is generated automatically. |
Example
curl -X POST https://api.salesbooth.com/v1/sandbox/simulate_webhook \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"event": "deal.closed",
"data": {
"deal_id": "deal_test_abc123",
"total": "2500.00",
"currency": "USD"
}
}'
Response
{
"error": false,
"data": {
"action": "simulate_webhook",
"environment": "test",
"sandbox": true,
"event": "deal.closed",
"deliveries": 2,
"webhook_ids": ["wh_xxxxx", "wh_yyyyy"],
"message": "Dispatched 'deal.closed' event to 2 webhook(s)."
}
}
Check the current state of your sandbox environment. Returns counts of test data across all entity types.
Example
curl https://api.salesbooth.com/v1/sandbox/status \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"environment": "test",
"sandbox": true,
"counts": {
"deals": 10,
"customers": 5,
"products": 10,
"contracts": 1,
"deal_escrow": 0
},
"total_test_records": 26
}
}
Playground API
The Playground API provisions ephemeral sandbox keys for the interactive API playground. Keys are auto-generated with limited scopes and expire after 2 hours. No authentication required — playground sessions are inherently sandboxed. Rate limited to 10 sessions per hour per IP.
Create an ephemeral playground session. Returns a temporary sb_test_* API key with sandbox scopes that expires in 2 hours. Sandbox data is automatically seeded on first use. No authentication required.
Example
curl -X POST https://api.salesbooth.com/v1/playground/session \
-H "Content-Type: application/json"
Response (200)
{
"error": false,
"data": {
"api_key": "sb_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"key_prefix": "sb_test_xxxx",
"expires_at": "2026-03-24T12:00:00Z",
"expires_in": 7200,
"environment": "test",
"sandbox": true,
"scopes": ["deals:read", "deals:write", "customers:read", "customers:write", "products:read", "contracts:read", "webhooks:read", "sandbox:read", "sandbox:write"],
"seeded": true
}
}
Check whether a playground session key is still valid. Pass the key prefix to look up its expiry status. No authentication required.
| Parameter | Type | Description |
| key_prefix required | string | First 12 characters of the playground API key (min 8 chars) |
Example
curl "https://api.salesbooth.com/v1/playground/session?key_prefix=sb_test_xxxx"
Response (200)
{
"error": false,
"data": {
"valid": true,
"expires_at": "2026-03-24T12:00:00Z",
"reason": null
}
}
Saved Configurations
Save product configuration snapshots with shareable short codes. Buyers can build a configuration in the widget, save it, share it via URL, and later convert it into a deal. Authenticated with a publishable key (sb_pub_*) via Bearer header.
Rate limits. Saves are limited to 10 per hour per IP. Reads are limited to 30 per minute per IP. Rate limit headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) are included in every response.
Short Codes
Each saved configuration receives a unique short code — an 8–16 character hex string (e.g. a3f8b21c). Short codes are used to retrieve and share configurations via URLs like https://salesbooth.com/configure/a3f8b21c.
Configurations expire after 30 days by default (configurable via expires_in, 1–365 days). Widget-level TTL defaults can be set in the widget configuration.
Save a product configuration snapshot. Returns a short code and shareable URL.
| Field | Description |
| product_selections required | Array of product selections with product_id, name, quantity, and configured_price |
| pricing_snapshot required | Pricing breakdown object (subtotals, discounts, taxes at time of configuration) |
| option_selections | Object mapping product IDs to their selected option values |
| subtotal | Total price as a number |
| currency | ISO 4217 currency code (default: USD) |
| customer_name | Buyer name (optional) |
| customer_email | Buyer email (optional) |
| customer_phone | Buyer phone number (optional) |
| booking_selections | Object with booking slot selections (optional) |
| expires_in | Expiration in days, 1–365 (default: 30) |
Example
curl -X POST https://api.salesbooth.com/v1/saved-configs \
-H "Authorization: Bearer sb_pub_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"product_selections": [
{
"product_id": "prod_abc123",
"name": "Pro Plan",
"quantity": 1,
"configured_price": 99.00
}
],
"pricing_snapshot": {
"subtotal": 99.00,
"tax": 8.17,
"total": 107.17
},
"subtotal": 99.00,
"currency": "USD",
"customer_email": "buyer@example.com",
"expires_in": 14
}'
Response (201)
{
"error": false,
"success": true,
"data": {
"short_code": "a3f8b21c",
"share_url": "https://salesbooth.com/configure/a3f8b21c",
"expires_at": "2026-03-22 14:30:00",
"created_at": "2026-03-08 14:30:00"
}
}
Retrieve a saved configuration by its short code. Includes price change detection — if product prices have changed since the configuration was saved, the price_changes array will list the differences.
| Parameter | Description |
| code required | The 8–16 character hex short code |
Example
curl https://api.salesbooth.com/v1/saved-configs?code=a3f8b21c \
-H "Authorization: Bearer sb_pub_xxxxx"
Response
{
"error": false,
"success": true,
"data": {
"short_code": "a3f8b21c",
"widget_id": "wgt_xxxxx",
"product_selections": [...],
"pricing_snapshot": {...},
"subtotal": 99.00,
"currency": "USD",
"expired": false,
"expires_at": "2026-03-22 14:30:00",
"share_url": "https://salesbooth.com/configure/a3f8b21c",
"price_changes": []
}
}
Update mutable fields of a saved configuration. Authenticated with a publishable API key (sb_pub_*).
| Field | Description |
| customer_name | Buyer name |
| customer_email | Buyer email address |
| customer_phone | Buyer phone number |
| option_selections | Object mapping product IDs to their selected option values |
| booking_selections | Object with booking slot selections |
Example
curl -X PATCH "https://api.salesbooth.com/v1/saved-configs?id=a3f8b21c" \
-H "Authorization: Bearer sb_pub_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"customer_name": "Jane Smith",
"customer_email": "jane@example.com"
}'
Permanently delete a saved configuration by its short code. Authenticated with a publishable API key (sb_pub_*).
Example
curl -X DELETE "https://api.salesbooth.com/v1/saved-configs?id=a3f8b21c" \
-H "Authorization: Bearer sb_pub_xxxxx"
Convert a saved configuration into a deal. Creates a customer record, a draft deal with line items, and applies any discounts from the pricing snapshot. Returns 409 if already converted, 410 if expired.
| Field | Description |
| short_code required | The short code of the saved configuration |
| customer_name required | Buyer name (overrides saved value if provided) |
| customer_email required | Buyer email (overrides saved value if provided) |
| customer_phone | Buyer phone number |
Example
curl -X POST https://api.salesbooth.com/v1/saved-configs?action=to_deal \
-H "Authorization: Bearer sb_pub_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"short_code": "a3f8b21c",
"customer_name": "Jane Smith",
"customer_email": "jane@example.com"
}'
Response (201)
{
"error": false,
"success": true,
"data": {
"deal_id": "deal_xxxxx",
"deal": { ... },
"converted_from": "a3f8b21c"
}
}
Uploads
Upload image files for products, option swatches, and other assets.
Upload an image file. Accepts JPEG, PNG, GIF, and WebP formats. Max file size: 2 MB.
Example
curl -X POST https://api.salesbooth.com/v1/uploads \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-F "file=@product-image.jpg"
Response (201)
{
"error": false,
"data": {
"url": "https://salesbooth.com/uploads/img_abc123.jpg",
"filename": "product-image.jpg",
"size": 145280,
"mime_type": "image/jpeg"
}
}
Credits
Prepaid credit balance management. Check balance, top up via Stripe Checkout, view ledger history, and estimate deal costs.
Get current credit balance.
Example
curl https://api.salesbooth.com/v1/credits \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"balance": 5000,
"low_balance_threshold": 100,
"is_low": false,
"can_create_deals": true,
"cost_per_deal": 1
}
}
Get credit ledger history showing all credit and debit transactions.
| Parameter | Type | Description |
| limit | integer | Max results (default: 25) |
| offset | integer | Pagination offset |
| type | string | Filter: credit or debit |
Example
curl https://api.salesbooth.com/v1/credits?action=ledger&limit=10 \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Create a Stripe Checkout session to top up credits.
| Field | Type | Description |
| amount required | number | Number of credits to purchase |
| success_url | string | Redirect URL on success |
| cancel_url | string | Redirect URL on cancel |
Example
curl -X POST https://api.salesbooth.com/v1/credits?action=topup \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "amount": 1000 }'
Estimate the credit cost for a deal before committing.
| Field | Type | Description |
| deal_id | string | Deal to estimate cost for |
Example
curl -X POST https://api.salesbooth.com/v1/credits?action=estimate \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "deal_id": "deal_abc123" }'
Billing
Billing dashboard endpoints for credit balance, usage charts, transaction ledger, invoices, auto top-up configuration, and alert settings.
Get billing dashboard data including balance, usage summary, and auto top-up status.
Example
curl https://api.salesbooth.com/v1/billing \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Get daily usage data for charts and trend analysis.
| Parameter | Type | Description |
| days | integer | Lookback period in days (default: 30) |
Example
curl https://api.salesbooth.com/v1/billing?action=usage-daily&days=14 \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Configure automatic credit top-up when balance falls below a threshold.
| Field | Type | Description |
| enabled required | boolean | Enable or disable auto top-up |
| threshold | integer | Trigger when balance drops below this |
| amount | integer | Credits to purchase on trigger |
Example
curl -X POST https://api.salesbooth.com/v1/billing?action=auto-topup \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "enabled": true, "threshold": 100, "amount": 500 }'
Configure low-balance alert notifications.
Example
curl -X POST https://api.salesbooth.com/v1/billing?action=alert-settings \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "low_balance_threshold": 50, "notify_email": true }'
Retrieve paginated credit transaction history for the tenant.
| Parameter | Type | Description |
| limit | integer | Number of entries per page (default: 25, max: 100) |
| offset | integer | Offset for pagination (default: 0) |
| type | string | Filter by entry type: credit or debit |
Example
curl "https://api.salesbooth.com/v1/billing?action=ledger&limit=25&offset=0" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Export the credit ledger as a CSV download.
| Parameter | Type | Description |
| type | string | Filter by entry type: credit or debit |
Example
curl "https://api.salesbooth.com/v1/billing?action=export-ledger" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Retrieve a paginated list of invoices for the tenant.
| Parameter | Type | Description |
| limit | integer | Number of invoices per page (default: 25, max: 100) |
| offset | integer | Offset for pagination (default: 0) |
Example
curl "https://api.salesbooth.com/v1/billing?action=invoices&limit=25" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Download a specific invoice as a PDF.
| Parameter | Type | Description |
| id required | string | Invoice ID to download |
Example
curl "https://api.salesbooth.com/v1/billing?action=invoice-pdf&id=inv_abc123" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Retrieve the paginated audit log of automatic top-up events.
| Parameter | Type | Description |
| limit | integer | Number of entries per page (default: 25, max: 100) |
| offset | integer | Offset for pagination (default: 0) |
Example
curl "https://api.salesbooth.com/v1/billing?action=auto-topup-log&limit=25" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Create a Stripe Checkout session to add credits to the account.
| Field | Type | Description |
| amount required | number | Top-up amount in USD (min: $5, max: $10,000) |
| success_url required | string | URL to redirect to after successful payment |
| cancel_url required | string | URL to redirect to if payment is cancelled |
Example
curl -X POST https://api.salesbooth.com/v1/billing?action=topup \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "amount": 50, "success_url": "https://app.example.com/billing?topup=success", "cancel_url": "https://app.example.com/billing" }'
Create a Stripe Setup Intent to save a payment method for future auto top-ups. No request body fields are required.
Example
curl -X POST https://api.salesbooth.com/v1/billing?action=setup-intent \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{}'
Team
Manage team members and roles. Invite users, update roles, and remove team members.
List all team members with their roles and invitation status.
Example
curl https://api.salesbooth.com/v1/team \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Invite a new team member via email.
| Field | Type | Description |
| email required | string | Email address to invite |
| role required | string | admin, member, or viewer |
Example
curl -X POST https://api.salesbooth.com/v1/team \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "email": "colleague@example.com", "role": "member" }'
Update a team member’s role.
| Field | Type | Description |
| membership_id required | integer | Team membership identifier |
| role required | string | New role: admin, member, or viewer |
Example
curl -X PATCH https://api.salesbooth.com/v1/team \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "membership_id": "tm_xxxxx", "role": "admin" }'
Remove a team member.
Example
curl -X DELETE "https://api.salesbooth.com/v1/team?id=tm_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Trust Levels
View your tenant’s trust status, progress metrics, auto top-up ceilings, and level change history.
Get the current tenant trust level, score, and progression details.
Example
curl https://api.salesbooth.com/v1/trust \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": {
"level": "established",
"score": 85,
"auto_topup_ceiling": 10000,
"next_level": "premium",
"next_level_score": 90
}
}
Get the history of trust level changes for the tenant.
| Parameter | Type | Description |
| limit | integer | Max results (default: 50) |
| offset | integer | Pagination offset |
Example
curl https://api.salesbooth.com/v1/trust?action=history \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Retrieve the list of revoked agent credentials and trust demotions. Public endpoint — no authentication required. Remote instances call this during federation to verify that incoming credentials have not been revoked since issuance.
Example
curl "https://api.salesbooth.com/v1/trust/revocations"
Response
{
"error": false,
"data": {
"revocations": [
{
"credential_id": "cred_abc123",
"revoked_at": "2026-02-10T08:00:00Z",
"reason": "trust_demotion"
}
],
"updated_at": "2026-03-18T12:00:00Z"
}
}
Sites
Create and manage tenant websites. Each site can have multiple pages and AI-generated content. Sites are used for deal landing pages, product showcases, and customer portals.
List all sites for the tenant, or retrieve a specific site by ID.
| Parameter | Type | Description |
| id | string | Retrieve a specific site |
Example
curl https://api.salesbooth.com/v1/sites \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Create a new site.
| Field | Type | Description |
| domain required | string | Domain for the site (subdomain or custom domain) |
| name | string | Site display name |
| status | string | active, inactive, or coming_soon |
| settings | object | Optional site settings object |
Example
curl -X POST https://api.salesbooth.com/v1/sites \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Enterprise Portal",
"domain": "acme.salesbooth.com",
"status": "coming_soon"
}'
Update site settings, status, or domain configuration.
Example
curl -X PATCH "https://api.salesbooth.com/v1/sites?id=site_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "status": "active" }'
Delete a site and all its pages.
Example
curl -X DELETE "https://api.salesbooth.com/v1/sites?id=site_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Site Pages
Create and manage individual pages within a site. Pages contain HTML content generated by AI or edited manually.
List all pages for a site, or retrieve a specific page.
| Parameter | Type | Description |
| id | string | Retrieve a specific page |
| site_id | string | Filter pages by site |
Example
curl "https://api.salesbooth.com/v1/site-pages?site_id=site_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Create a new page within a site.
| Field | Type | Description |
| site_id required | string | The parent site |
| title required | string | Page title |
| slug | string | URL slug (auto-generated from title if omitted) |
| content | string | Page HTML content |
| status | string | draft or published |
Example
curl -X POST https://api.salesbooth.com/v1/site-pages \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"site_id": "site_xxxxx",
"title": "Enterprise Pricing",
"slug": "pricing",
"status": "published"
}'
Update a page’s content, title, or status.
Example
curl -X PATCH "https://api.salesbooth.com/v1/site-pages?id=page_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "status": "published", "title": "Updated Pricing Page" }'
Delete a site page.
Example
curl -X DELETE "https://api.salesbooth.com/v1/site-pages?id=page_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Site Suggestions
AI-driven optimization recommendations for your sites. The system analyzes session replays and conversion data to generate actionable suggestions. Accept or reject suggestions to apply or dismiss them, with rollback support.
List optimization suggestions, or retrieve a specific suggestion. Pass insights=1 for acceptance rates and impact benchmarks, or health_score=1&site_id=x for a site’s optimization health score.
| Parameter | Type | Description |
| id | string | Retrieve a specific suggestion |
| site_id | string | Filter by site |
| status | string | Filter: pending, accepted, rejected |
| insights | string | Set to 1 to get learning insights (acceptance rates, impact benchmarks) |
Example
curl "https://api.salesbooth.com/v1/site-suggestions?site_id=site_xxxxx&status=pending" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Accept, reject, or rollback an optimization suggestion.
| Field | Type | Description |
| action required | string | accept, reject, or rollback |
Example — Accept a suggestion
curl -X PATCH "https://api.salesbooth.com/v1/site-suggestions?id=sugg_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "action": "accept" }'
Batch accept or reject suggestions, update optimizer settings, trigger analysis, or export suggestions.
| Field | Type | Description |
| action required | string | batch, settings, analyze, export, or ab_test |
| suggestion_ids | array | For batch: array of suggestion IDs |
| batch_action | string | For batch: accept or reject |
Example — Batch accept
curl -X POST https://api.salesbooth.com/v1/site-suggestions \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"action": "batch",
"suggestion_ids": ["sugg_aaa", "sugg_bbb"],
"batch_action": "accept"
}'
Plugins
Browse the plugin marketplace and manage installed plugins. Plugins extend platform functionality with features like analytics, website builder, channel integrations, and more.
List available plugins in the marketplace, or list installed plugins for the tenant.
| Parameter | Type | Description |
| installed | boolean | Set to 1 to list only installed plugins |
Example
curl https://api.salesbooth.com/v1/plugins?installed=1 \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"data": [
{
"id": "analytics",
"name": "Analytics",
"description": "Session replays, conversion funnels, and heatmaps",
"installed": true,
"version": "1.2.0"
}
]
}
Install a plugin for the current tenant.
| Field | Type | Description |
| plugin_id required | string | Plugin identifier from the marketplace listing |
Example
curl -X POST https://api.salesbooth.com/v1/plugins \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "plugin_id": "analytics" }'
Uninstall a plugin from the current tenant.
Example
curl -X DELETE "https://api.salesbooth.com/v1/plugins?id=analytics" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
GDPR Compliance
Endpoints for GDPR data subject rights: right of access (Art. 15), data portability (Art. 20), right to erasure (Art. 17), consent management, and compliance monitoring. All actions are logged in the audit trail.
Anonymisation, not deletion. Financial records (deals, contracts, payments) are preserved for legal and accounting requirements but anonymised with a REDACTED-{hash} scheme. Customer PII is fully erased. The audit trail records every erasure action for compliance verification.
Required Scopes
| customers:read | Required for data export, consent retrieval, erasure verification, dashboard, and processing register |
| customers:write | Required for erasure, consent recording, consent withdrawal, and retention policy updates |
Data Subject Rights
Endpoints supporting data subject access requests (DSARs) and the right to be forgotten.
Export all data held about a customer (Art. 15 Right of Access / Art. 20 Data Portability). Returns customer profile, deals, contracts, consent records, communications, and audit trail in a portable JSON format.
| Parameter | Type | Description |
| customer_id required | string | The customer identifier |
Example
curl "https://api.salesbooth.com/v1/gdpr/export?customer_id=cust_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Erase customer personal data within the local system (Art. 17 Right to Erasure). PII is removed from the customer record. Financial records in deals and contracts are anonymised with REDACTED-{hash} to preserve accounting integrity. Does not propagate to external systems — use /gdpr/full_erase for cross-system erasure.
| Parameter | Type | Description |
| customer_id required | string | The customer identifier |
| Body Field | Type | Description |
| reason | string | Reason for erasure (logged in audit trail, default: “GDPR erasure request”) |
Example
curl -X DELETE "https://api.salesbooth.com/v1/gdpr/erase?customer_id=cust_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"reason": "Customer requested data deletion"}'
Full cross-system GDPR erasure (Art. 17 Right to be Forgotten). Atomically erases all customer PII across all systems: customer record, deals, contracts, communication logs, audit trail, consent records, webhook payloads, and search indexes.
| Parameter | Type | Description |
| customer_id required | string | The customer identifier |
| Body Field | Type | Description |
| reason | string | Reason for erasure (default: “GDPR full erasure request”) |
Example
curl -X DELETE "https://api.salesbooth.com/v1/gdpr/full_erase?customer_id=cust_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"reason": "Customer right to be forgotten request"}'
Verify that a customer’s data has been completely erased. Scans all tables for remaining PII and returns a verification report.
| Parameter | Type | Description |
| customer_id required | string | The customer identifier to verify |
Example
curl "https://api.salesbooth.com/v1/gdpr/verify?customer_id=cust_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Consent Management
Record, retrieve, withdraw, and renew consent for specific processing purposes.
Retrieve consent records for a customer. Returns all consent entries with their current status and the list of valid consent purposes.
| Parameter | Type | Description |
| customer_id required | string | The customer identifier |
| active_only | string | Set to true to return only active consents |
Example
curl "https://api.salesbooth.com/v1/gdpr/consent?customer_id=cust_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Record a new consent grant for a customer and purpose. Supports optional channel and consent version metadata.
| Field | Type | Description |
| customer_id required | string | The customer identifier |
| purpose required | string | Processing purpose (e.g. marketing, analytics, necessary) |
| channel | string | How consent was collected (default: api) |
| metadata | object | Additional context about the consent |
| consent_version | string | Version of the consent policy |
Example
curl -X POST https://api.salesbooth.com/v1/gdpr/consent \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cust_xxxxx",
"purpose": "marketing",
"channel": "web_form",
"consent_version": "2.0"
}'
Withdraw an existing consent record for a customer and purpose.
| Parameter | Type | Description |
| customer_id required | string | The customer identifier |
| Body Field | Type | Description |
| purpose required | string | The consent purpose to withdraw |
Example
curl -X DELETE "https://api.salesbooth.com/v1/gdpr/consent?customer_id=cust_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"purpose": "marketing"}'
Batch withdraw all active consent records for a customer in a single operation.
| Field | Type | Description |
| customer_id required | string | The customer identifier |
| reason | string | Reason for withdrawal (default: “Batch consent withdrawal”) |
Example
curl -X POST https://api.salesbooth.com/v1/gdpr/consent_withdraw_all \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"customer_id": "cust_xxxxx", "reason": "Customer opted out"}'
Extend the expiration of an existing consent record for a customer and purpose. Creates a new audit entry distinct from the initial grant.
| Field | Type | Description |
| customer_id required | string | The customer identifier |
| purpose required | string | The consent purpose to renew |
| channel | string | Renewal channel (default: api) |
| expiration_months | integer | Custom expiration period in months (uses purpose default if omitted) |
Example
curl -X POST https://api.salesbooth.com/v1/gdpr/consent_renew \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"customer_id": "cust_xxxxx", "purpose": "marketing", "expiration_months": 12}'
Renew all active or expired (non-withdrawn) consents for a customer in a single operation.
| Field | Type | Description |
| customer_id required | string | The customer identifier |
| channel | string | Renewal channel (default: api) |
Example
curl -X POST https://api.salesbooth.com/v1/gdpr/consent_renew_all \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"customer_id": "cust_xxxxx", "channel": "re-consent-campaign"}'
Returns consent records that will expire within the specified number of days. Useful for triggering re-consent campaigns before expiry.
| Parameter | Type | Description |
| days_ahead | integer | Look-ahead window in days (default: 30, max: 365) |
| limit | integer | Maximum records to return (default: 100, max: 500) |
Example
curl "https://api.salesbooth.com/v1/gdpr/consent_expiring?days_ahead=14" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Returns aggregate consent health metrics including active, expiring, expired, and withdrawn counts with an overall health percentage score.
Example
curl https://api.salesbooth.com/v1/gdpr/consent_health \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Returns the per-purpose consent expiration configuration for the current tenant, merged with global defaults.
Example
curl https://api.salesbooth.com/v1/gdpr/consent_expiration_config \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Set the default expiration period for a specific consent purpose for the current tenant.
| Field | Type | Description |
| purpose required | string | The consent purpose to configure |
| expiration_months required | integer | Expiration period in months (1–120) |
Example
curl -X POST https://api.salesbooth.com/v1/gdpr/consent_expiration_config \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"purpose": "marketing", "expiration_months": 12}'
Returns all valid consent purposes with human-readable labels and default expiration periods in months.
Example
curl https://api.salesbooth.com/v1/gdpr/consent_purposes \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Retention Policies
View and manage data retention policies. Retention policies control how long different types of data are kept before automatic cleanup.
Returns all data retention policies for the current tenant, along with valid data types.
Example
curl https://api.salesbooth.com/v1/gdpr/retention \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Creates or updates a data retention policy for a specific data type.
| Field | Type | Description |
| data_type required | string | The data type to configure retention for |
| retention_days required | integer | Number of days to retain data |
| is_active | boolean | Whether the policy is active (default: true) |
Example
curl -X PATCH https://api.salesbooth.com/v1/gdpr/retention \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"data_type": "audit_logs",
"retention_days": 730,
"is_active": true
}'
Compliance Monitoring
Dashboards, reports, and audit evidence for GDPR compliance oversight.
Returns aggregate compliance data: consent health metrics, recent DSARs (last 30 days), and erasure statistics. Suitable for the compliance overview panel.
Example
curl https://api.salesbooth.com/v1/gdpr/dashboard \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Returns all active entries from the data processing register (Art. 30 Records of Processing Activities). Includes data categories, processing purposes, legal bases, retention periods, and data recipients.
Example
curl https://api.salesbooth.com/v1/gdpr/register \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Returns paginated list of erasure and export audit log entries for the current tenant.
| Parameter | Type | Description |
| offset | integer | Number of entries to skip (default: 0) |
| limit | integer | Maximum entries to return (default: 50, max: 100) |
Example
curl "https://api.salesbooth.com/v1/gdpr/erasure_log?limit=25" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Search customers by name, email, or ID using blind indexes, and overlay compliance context per result: active consent count and consent purposes held.
| Parameter | Type | Description |
| q required | string | Search query (name, email, or customer ID) |
| limit | integer | Maximum results (default: 10, max: 20) |
Example
curl "https://api.salesbooth.com/v1/gdpr/search?q=jane%40example.com" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Returns a structured compliance evidence report for a given date range, including DSAR log, erasure summary, consent health snapshot, and retention policies. Suitable for regulator submission.
| Parameter | Type | Description |
| date_from | string | Start of date range, YYYY-MM-DD (defaults to 30 days ago) |
| date_to | string | End of date range, YYYY-MM-DD (defaults to today) |
Example
curl "https://api.salesbooth.com/v1/gdpr/audit_evidence?date_from=2026-01-01&date_to=2026-03-31" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Compliance & GDPR Flows
Step-by-step consent lifecycle and data subject request (DSAR) flows with complete curl examples. All compliance actions are logged in the immutable audit trail for regulatory evidence.
Consent Lifecycle
Consent follows a four-step lifecycle: record → check → withdraw → renew. All steps are idempotent and generate audit trail entries.
Step 1 — Record consent at sign-up
curl -X POST https://api.salesbooth.com/v1/gdpr/consent \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cust_xxxxx",
"purpose": "marketing_email",
"channel": "web_form",
"consent_version": "2.1",
"metadata": { "ip": "1.2.3.4", "form": "signup" }
}'
Step 2 — Check active consents before sending
curl "https://api.salesbooth.com/v1/gdpr/consent?customer_id=cust_xxxxx&active_only=true" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
# Response includes:
# { "consents": [{ "purpose": "marketing_email", "status": "active",
# "expires_at": "2028-03-01", ... }],
# "valid_purposes": ["marketing_email", "marketing_sms", ...] }
Step 3 — Withdraw consent on unsubscribe
curl -X DELETE "https://api.salesbooth.com/v1/gdpr/consent?customer_id=cust_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"purpose": "marketing_email"}'
Step 4 — Renew consent before expiry
curl -X POST https://api.salesbooth.com/v1/gdpr/consent_renew \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cust_xxxxx",
"purpose": "marketing_email",
"channel": "re-consent-email",
"expiration_months": 24
}'
Data Export Flow (Art. 15/20)
Export all data held about a customer in portable JSON format. The export is logged in the audit trail.
# Request export
curl "https://api.salesbooth.com/v1/gdpr/export?customer_id=cust_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
# Response shape:
# { "export": {
# "customer": { "customer_id": "cust_xxxxx", "name": "...", "email": "...", ... },
# "deals": [...],
# "contracts": [...],
# "consents": [...],
# "audit_trail": [...],
# "exported_at": "2026-03-18T10:00:00+00:00"
# }
# }
Erasure Flow (Art. 17)
Erase a customer’s PII. Financial records are anonymised (not deleted) to preserve accounting integrity. Use /gdpr/verify to confirm erasure completion.
# Request erasure
curl -X DELETE "https://api.salesbooth.com/v1/gdpr/full_erase?customer_id=cust_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{"reason": "Customer exercised right to be forgotten"}'
# Verify erasure
curl "https://api.salesbooth.com/v1/gdpr/verify?customer_id=cust_xxxxx" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
# Verify response includes a verification_hash for the audit record:
# { "verification": {
# "erased": true,
# "tables_checked": 12,
# "pii_remaining": 0,
# "verification_hash": "sha256:a1b2c3..."
# }
# }
Audit Trail Integrity
Every audit entry is linked to the previous one via a SHA-256 hash chain, forming a tamper-evident log. The hash formula is:
entry_hash = SHA256(
entity_type + entity_id + action
+ changes_json + snapshot_json
+ previous_hash <-- links to previous entry
+ created_at
)
Any attempt to modify or delete an entry breaks the chain. The GET /api/v1/audit?action=verify&entity_type=customer&entity_id=cust_xxxxx endpoint re-computes the chain and returns a status of intact or tampered.
Compliance Evidence
Enterprise procurement and legal teams require structured evidence of GDPR compliance before approving software vendors. The compliance evidence endpoint returns a point-in-time package covering all key compliance dimensions.
Returns a structured compliance package suitable for enterprise procurement reviews and regulator submission. Covers retention policy status, consent statistics per purpose, recent erasure log with verification hashes, audit trail integrity check (hash chain), and data processing register summary (Art. 30 ROPA).
Required scope
customers:read
Example request
curl https://api.salesbooth.com/v1/gdpr/compliance_evidence \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response shape
{
"error": false,
"success": true,
"data": {
"evidence": {
"report_type": "compliance_evidence",
"generated_at": "2026-03-18T10:00:00+00:00",
"tenant_id": "tenant_xxxxx",
"retention_policies": {
"policies": [
{ "data_type": "audit_logs", "retention_days": 730,
"is_active": true, "compliance_status": "active" }
],
"overall_compliant": true,
"policy_count": 5
},
"consent_statistics": {
"by_purpose": {
"marketing_email": {
"granted": 1420, "withdrawn": 83, "expired": 12,
"expiring_soon": 47, "total": 1562
},
"analytics": {
"granted": 1380, "withdrawn": 31, "expired": 8,
"expiring_soon": 22, "total": 1441
}
},
"purpose_count": 6
},
"erasure_log": {
"recent_entries": [
{ "log_id": "audit_abc123", "entity_id": "cust_xxxxx",
"action": "erased", "actor_type": "api_key",
"entry_hash": "sha256:a1b2c3...", "created_at": "2026-03-15 09:12:00" }
],
"entry_count": 12
},
"audit_integrity": {
"status": "verified", // "verified" | "broken" | "unavailable"
"checked_entries": 100,
"broken_entries": 0,
"sample_size": 100
},
"data_processing_register": {
"total_entries": 8,
"data_categories": ["contact_data", "financial_data", "usage_data"],
"legal_bases": ["consent", "contract", "legitimate_interest"]
}
}
}
}
Enterprise tip: Run this endpoint quarterly and store the response as a compliance snapshot. The audit_integrity.status field is especially useful for demonstrating tamper-evidence to auditors. A broken status triggers an immediate security review.
Webhook Signature Verification
Every webhook delivery includes two headers: X-Salesbooth-Signature (HMAC-SHA256 of the timestamp + raw body) and X-Salesbooth-Timestamp (Unix timestamp of delivery). Verify both before processing any webhook payload to prevent spoofed and replayed requests.
Algorithm: v1= + HMAC-SHA256(webhook_secret, timestamp + "." + raw_request_body). The webhook secret is per-webhook and is set at creation time. Never log or expose the secret. Rotate it from the webhook settings page if compromised.
Verification — PHP
PHP
<?php
define('WEBHOOK_SECRET', getenv('SALESBOOTH_WEBHOOK_SECRET'));
define('TOLERANCE_SECONDS', 300);
// Read the raw request body (must be read BEFORE parsing JSON)
$rawBody = file_get_contents('php://input');
// Get the signature and timestamp headers
$signature = $_SERVER['HTTP_X_SALESBOOTH_SIGNATURE'] ?? '';
$ts = $_SERVER['HTTP_X_SALESBOOTH_TIMESTAMP'] ?? '';
// Replay protection: reject events older than 5 minutes
if (abs(time() - (int) $ts) > TOLERANCE_SECONDS) {
http_response_code(400);
exit(json_encode(['error' => 'Timestamp out of tolerance']));
}
// Compute expected signature: v1= + HMAC-SHA256(timestamp.body, secret)
$signedContent = $ts . '.' . $rawBody;
$expected = 'v1=' . hash_hmac('sha256', $signedContent, WEBHOOK_SECRET);
// Constant-time comparison to prevent timing attacks
if (!hash_equals($expected, $signature)) {
http_response_code(401);
exit(json_encode(['error' => 'Invalid signature']));
}
// Safe to parse and process the payload
$event = json_decode($rawBody, true);
$eventType = $event['event']; // e.g. "deal.closed"
$data = $event['data'];
switch ($eventType) {
case 'deal.closed':
// Handle deal closure
break;
case 'customer.deleted':
// Handle GDPR erasure notification
break;
}
Verification — Python
Python
import hmac
import hashlib
import os
import time
from flask import Flask, request, abort
import json
app = Flask(__name__)
WEBHOOK_SECRET = os.environ['SALESBOOTH_WEBHOOK_SECRET']
TOLERANCE_SECONDS = 300
@app.route('/webhook', methods=['POST'])
def webhook():
# Read raw body before any parsing
raw_body = request.get_data()
# Get signature and timestamp headers
signature = request.headers.get('X-Salesbooth-Signature', '')
ts = request.headers.get('X-Salesbooth-Timestamp', '0')
# Replay protection: reject events older than 5 minutes
if abs(time.time() - int(ts)) > TOLERANCE_SECONDS:
abort(400, 'Timestamp out of tolerance')
# Compute expected signature: v1= + HMAC-SHA256(timestamp.body, secret)
signed_content = f"{ts}.".encode('utf-8') + raw_body
expected = 'v1=' + hmac.new(
WEBHOOK_SECRET.encode('utf-8'),
signed_content,
hashlib.sha256
).hexdigest()
# Constant-time comparison
if not hmac.compare_digest(expected, signature):
abort(401, 'Invalid signature')
event = json.loads(raw_body)
event_type = event.get('event') # e.g. "deal.closed"
data = event.get('data')
if event_type == 'deal.closed':
handle_deal_closed(data)
elif event_type == 'customer.deleted':
handle_customer_deletion(data)
return '', 200
Verification — JavaScript (Node.js)
JavaScript (Express)
import express from 'express';
import crypto from 'crypto';
const app = express();
const WEBHOOK_SECRET = process.env.SALESBOOTH_WEBHOOK_SECRET;
const TOLERANCE_SECONDS = 300;
// IMPORTANT: Use express.raw() to get the raw body before any JSON parsing
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const rawBody = req.body; // Buffer from express.raw()
const signature = req.headers['x-salesbooth-signature'] || '';
const timestamp = req.headers['x-salesbooth-timestamp'] || '0';
// Replay protection: reject events older than 5 minutes
const age = Math.floor(Date.now() / 1000) - parseInt(timestamp, 10);
if (age > TOLERANCE_SECONDS) {
return res.status(400).json({ error: 'Timestamp out of tolerance' });
}
// Compute expected signature: v1= + HMAC-SHA256(timestamp.body, secret)
const signedContent = `${timestamp}.${rawBody.toString('utf8')}`;
const expected = 'v1=' + crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(signedContent, 'utf8')
.digest('hex');
// Constant-time comparison to prevent timing attacks
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(rawBody.toString());
const { event: eventType, data } = event;
switch (eventType) {
case 'deal.closed':
handleDealClosed(data);
break;
case 'customer.deleted':
handleCustomerDeleted(data);
break;
}
res.status(200).end();
});
Security notes:
- Always read the raw body before any JSON parsing — even whitespace differences will invalidate the signature.
- Include both the timestamp and body in the signed content (
timestamp + "." + raw_body) and prefix the result with v1=.
- Reject stale events where
X-Salesbooth-Timestamp is older than 300 seconds to prevent replay attacks.
- Use constant-time comparison (
hash_equals in PHP, hmac.compare_digest in Python, crypto.timingSafeEqual in Node.js) to prevent timing attacks.
- Return
2xx quickly and process asynchronously — webhooks time out after 10 seconds.
- Implement idempotency using
event_id to handle duplicate deliveries.
Customer Authentication
Magic-link authentication for the Customer Portal. Customers receive a time-limited login link via email and exchange it for a short-lived JWT session. No seller API key is required — this endpoint is fully public.
Rate limiting: Magic-link requests are limited to 3 per minute per email+IP to prevent enumeration. A 200 response is returned even when the email is not found.
Send a magic-link login email to a customer. Returns 200 regardless of whether the email exists to prevent enumeration.
| Field | Type | Description |
| email required | string | Customer email address |
Example
curl -X POST https://api.salesbooth.com/v1/customer-auth?action=request-access \
-H "Content-Type: application/json" \
-d '{ "email": "customer@example.com" }'
Response
{
"error": false,
"success": true,
"data": { "message": "If this email is registered, a login link has been sent." }
}
Exchange a magic-link token (from the email link) for a JWT access token and refresh token.
| Field | Type | Description |
| token required | string | One-time token from the magic link |
Example
curl -X POST https://api.salesbooth.com/v1/customer-auth?action=verify \
-H "Content-Type: application/json" \
-d '{ "token": "clat_xxxxxxxxxxxxxxxxxxxxxxxx" }'
Response
{
"error": false,
"success": true,
"data": {
"access_token": "eyJ...",
"refresh_token": "clar_xxxxxxxxxxxxxxxx",
"expires_in": 3600,
"customer_id": "cust_xxxxx",
"tenant_id": "tenant_xxxxx"
}
}
Refresh an expired access token using the refresh token.
| Field | Type | Description |
| refresh_token required | string | Refresh token from the verify response |
Revoke the current customer session.
Customer Portal
Authenticated self-service endpoints for buyers. All requests require a valid customer JWT issued by Customer Authentication sent as a Bearer token. Covers deal viewing, contract signing, payment, and profile management.
Authentication: Authorization: Bearer <customer_jwt> — use the JWT from the verify response, not a seller API key.
List all deals belonging to the authenticated customer.
| Parameter | Type | Description |
| status | string | Filter by deal status |
| limit | integer | Max results (default: 20) |
| offset | integer | Pagination offset |
Get full deal details including line items, terms, and current status.
Retrieve the signed contract document for a deal.
Digitally sign a contract to accept the deal terms.
| Field | Type | Description |
| deal_id required | string | Deal to sign |
| signature_name required | string | Customer’s full name as signature |
| agreed required | boolean | Must be true to accept terms |
Create a Stripe PaymentIntent for a deal. Returns the client_secret needed by Stripe.js to complete the payment on the buyer’s side.
| Field | Type | Description |
| deal_id required | string | Deal to pay for |
Confirm payment completion after Stripe.js has collected and processed payment details.
| Field | Type | Description |
| deal_id required | string | Deal identifier |
| payment_intent_id required | string | Stripe PaymentIntent ID |
Get the customer’s own profile data.
Update the customer’s profile fields.
| Field | Type | Description |
| name | string | Display name |
| phone | string | Phone number |
| company | string | Company name |
List all active and past recurring subscriptions for the customer.
Retrieve portal configuration for a deal, including the Stripe publishable key and whether payments are enabled for the tenant. Used by the embedded customer portal to initialise Stripe.js.
| Parameter | Type | Description |
| deal_id required | string | Deal the customer is accessing |
Example
curl "https://api.salesbooth.com/v1/customer-portal?action=portal-config&deal_id=deal_xxxxx" \
-H "Authorization: Bearer <customer_jwt>"
Response
{
"error": false,
"success": true,
"data": {
"stripe_publishable_key": "pk_test_xxxxx",
"payment_enabled": true
}
}
List the authenticated customer’s consent records, including purpose, granted date, expiry status, and whether renewal is required.
Example
curl "https://api.salesbooth.com/v1/customer-portal?action=consents" \
-H "Authorization: Bearer <customer_jwt>"
Response
{
"error": false,
"success": true,
"data": {
"consents": [
{
"id": "con_xxxxx",
"purpose": "marketing",
"granted_at": "2025-12-01T10:00:00Z",
"expires_at": "2026-12-01T10:00:00Z",
"is_expired": false,
"renewal_required": false
}
]
}
}
Submit a change request for a deal. Notifies the seller and logs the request to the deal’s activity log. A deal.change_requested webhook event is dispatched on success.
| Field | Type | Description |
| deal_id required | string | Deal to request changes for |
| message | string | Description of the requested changes |
Example
curl -X POST "https://api.salesbooth.com/v1/customer-portal?action=request-changes" \
-H "Authorization: Bearer <customer_jwt>" \
-H "Content-Type: application/json" \
-d '{ "deal_id": "deal_xxxxx", "message": "Please adjust the payment schedule to monthly." }'
Response
{
"error": false,
"success": true,
"data": {
"deal_id": "deal_xxxxx",
"message": "Change request submitted"
}
}
Renew a specific consent by purpose. Extends the consent expiry date to the tenant-configured renewal period.
| Field | Type | Description |
| purpose required | string | Consent purpose to renew (e.g. marketing, data-processing) |
Example
curl -X POST "https://api.salesbooth.com/v1/customer-portal?action=consent-renew" \
-H "Authorization: Bearer <customer_jwt>" \
-H "Content-Type: application/json" \
-d '{ "purpose": "marketing" }'
Response
{
"error": false,
"success": true,
"data": {
"id": "con_xxxxx",
"purpose": "marketing",
"granted_at": "2026-05-16T10:00:00Z",
"expires_at": "2027-05-16T10:00:00Z"
}
}
Renew all of the customer’s consents at once. Useful for presenting a single “I agree to all” renewal prompt in the portal UI.
Example
curl -X POST "https://api.salesbooth.com/v1/customer-portal?action=consent-renew-all" \
-H "Authorization: Bearer <customer_jwt>"
Response
{
"error": false,
"success": true,
"data": {
"renewed_count": 3,
"consents": [
{ "purpose": "marketing", "expires_at": "2027-05-16T10:00:00Z" },
{ "purpose": "data-processing", "expires_at": "2027-05-16T10:00:00Z" }
]
}
}
Deal Discovery
Enables AI agents to search and browse available deal offers programmatically. This endpoint is agent-facing — it returns offers that the seller has marked as agent-discoverable, filtered by the agent’s criteria.
Required scope: agent:discover
Also available via MCP: The discover_deals MCP tool exposes the same data in a structured format for Claude and other MCP-compatible agents. See MCP Protocol.
Discover agent-visible deal offers with optional filters. Returns only products and deals that the merchant has explicitly enabled for agent discovery.
| Parameter | Type | Description |
| category | string | Filter by product category |
| min_price | number | Minimum deal price |
| max_price | number | Maximum deal price |
| currency | string | ISO 4217 currency code (e.g. USD) |
| pricing_model | string | Filter by pricing model type |
| limit | integer | Max results (default: 50, max: 100) |
| offset | integer | Pagination offset |
Example
curl "https://api.salesbooth.com/v1/deal-discovery?category=software&max_price=5000¤cy=USD" \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"deals": [
{
"deal_id": "deal_xxxxx",
"title": "Enterprise Software Suite",
"price": 2999.00,
"currency": "USD",
"category": "software",
"negotiable": true,
"terms_schema_url": "/api/v1/schema/deal-terms"
}
],
"pagination": { "total": 42, "limit": 50, "offset": 0, "count": 1 }
}
}
Retrieve the JSON Schema defining the structure of discoverable deal terms. Use this to validate deal proposals programmatically before submitting. See also
Machine-Readable Schemas.
Quotes & Invoices
Generate shareable quotes and invoices from deals. Quotes have a configurable validity window; invoices are permanent records. Both are retrievable via a short code without authentication, making them safe to share directly with customers.
Required scope: deals:read to generate quotes, deals:write to generate invoices. Short-code retrieval is unauthenticated.
Generate a quote from a deal. Returns a short code and shareable URL the customer can visit to view and accept the quote.
| Field | Type | Description |
| deal_id required | string | Deal to generate quote for |
| validity_days | integer | Days until quote expires (default: 30) |
Example
curl -X POST https://api.salesbooth.com/v1/quotes?action=generate_quote \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "deal_id": "deal_abc123", "validity_days": 14 }'
Response
{
"error": false,
"success": true,
"data": {
"quote_id": "qte_xxxxx",
"short_code": "q7f3a1b2",
"share_url": "https://salesbooth.com/quote/q7f3a1b2",
"expires_at": "2026-03-29T00:00:00Z",
"total": 2999.00,
"currency": "USD"
}
}
Generate a formal invoice from a closed deal.
| Field | Type | Description |
| deal_id required | string | Closed deal to invoice |
Retrieve a quote or invoice by its short code. No authentication required. Used by the customer-facing quote viewing page.
| Parameter | Type | Description |
| short_code required | string | The short code from the generate response |
List all quotes generated for a deal. Requires authentication.
Permanently delete a quote by its ID. Requires deals:write scope. Returns 404 if the quote is not found or does not belong to the current workspace.
| Parameter | Type | Description |
| id required | string | Quote ID to delete |
200
400
401
404
Deal Notifications
Send transactional notifications to customers about deal activity. Supports email and SMS channels based on customer contact preferences. Used by agents and automations to deliver quote links, payment reminders, and deal updates.
Required scope: customers:read (GET), deals:write (POST)
Rate limit: 10 notifications per hour per API key.
Get a customer’s notification channel preferences and recent notification history before sending.
| Parameter | Type | Description |
| customer_id required | string | Customer to check |
Response
{
"error": false,
"success": true,
"data": {
"preferred_channel": "email",
"has_email": true,
"has_phone": false,
"marketing_consent": true,
"recent_notifications": [...]
}
}
Send a transactional notification to a customer about a deal.
| Field | Type | Description |
| deal_id required | string | Related deal |
| type required | string | quote_sent, invoice_sent, payment_reminder, deal_update, terms_updated |
| message | string | Optional custom message body |
Example
curl -X POST https://api.salesbooth.com/v1/deal-notifications \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"deal_id": "deal_abc123",
"type": "quote_sent",
"message": "Your quote is ready — view it at https://salesbooth.com/quote/q7f3a1b2"
}'
Pricing Simulation
Read-only pricing tools for agents to model bundle discounts, compare cart scenarios, and analyse historical negotiation patterns — without creating real deals. Useful for recommending the optimal product configuration to buyers.
Required scope: products:read
All simulation responses include "simulation_only": true to confirm no data was written.
Simulate bundle pricing for a cart. Applies all matching bundle discount rules and promo codes without creating a deal.
| Field | Type | Description |
| items required | array | Array of { product_id, quantity, option_ids? } |
| currency | string | ISO 4217 code (default: USD) |
| promo_code | string | Optional promo code to test |
Example
curl -X POST https://api.salesbooth.com/v1/simulate-pricing \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "product_id": "prod_aaa", "quantity": 2 },
{ "product_id": "prod_bbb", "quantity": 1 }
],
"currency": "USD",
"promo_code": "SAVE20"
}'
Response
{
"error": false,
"success": true,
"data": {
"items": [...],
"subtotal": 450.00,
"bundle_discounts": [{ "rule": "3-for-2 Bundle", "amount": 45.00 }],
"bundle_discount_total": 45.00,
"promo_discount": 81.00,
"total": 324.00,
"currency": "USD",
"savings_vs_individual": 126.00,
"simulation_only": true
}
}
Compare pricing across multiple cart scenarios side-by-side. Useful for agents presenting options to buyers.
| Field | Type | Description |
| scenarios required | array | Array of { label, items } scenario objects |
| currency | string | ISO 4217 currency code |
Retrieve aggregated negotiation patterns for a product or category. Returns win rates, average discount depth, and deal velocity to inform agent negotiation strategy.
| Parameter | Type | Description |
| product_id | string | Analyse patterns for a specific product |
| category | string | Analyse patterns for a product category |
| period_days | integer | Lookback window in days (1–365, default: 90) |
Real-Time Events (SSE)
Subscribe to a real-time stream of deal events via Server-Sent Events (SSE). Use this to power live dashboards, notification UIs, or trigger agent actions without polling. The stream requires authentication and emits events for all event types the key has access to.
Protocol: Server-Sent Events (text/event-stream)
Max stream duration: 5 minutes. A reconnect event is sent before the connection closes so your client can reconnect from the last event.
Heartbeat: A heartbeat comment is sent every 15 seconds to keep the connection alive through load balancers and proxies.
Open a Server-Sent Events stream. Set Accept: text/event-stream and keep the connection open to receive events as they occur.
| Parameter | Type | Description |
| events | string | Comma-separated event types to subscribe to (e.g. deal.updated,negotiation.countered). Omit for all. |
| deal_id | string | Filter events to a specific deal |
| customer_id | string | Filter events for a specific customer |
| last_event_id | string | Resume from this event ID (also accepted via Last-Event-ID header) |
Example (curl)
curl -N "https://api.salesbooth.com/v1/events/stream?events=deal.updated,deal.closed" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Accept: text/event-stream"
Example (JavaScript EventSource)
// Note: the browser EventSource API does not support custom headers.
// Authenticate via the api_key query parameter instead.
const es = new EventSource(
'/api/v1/events/stream?events=deal.updated&api_key=sb_test_example_key_do_not_use'
);
es.addEventListener('deal.updated', (e) => {
const event = JSON.parse(e.data);
console.log('Deal updated:', event.deal_id);
});
es.addEventListener('reconnect', (e) => {
const { last_event_id } = JSON.parse(e.data);
// Reconnect with ?last_event_id= to resume
});
Stream event format
event: connected
data: {"status":"connected","connection_id":"conn_xxxxx","heartbeat_interval":15}
event: deal.updated
data: {"deal_id":"deal_abc","status":"in_progress","_timestamp":"2026-03-15T10:30:00Z","_signature":"sha256=..."}
: heartbeat 2026-03-15T10:30:15+00:00
event: reconnect
data: {"reason":"timeout","last_event_id":"seq:1234"}
Heartbeats are SSE comment lines (lines beginning with :). They keep the connection alive and reset proxy timeouts but are not dispatched as events by EventSource — no addEventListener('heartbeat', …) listener is needed.
FX Rates
Retrieve real-time exchange rates between any two currencies. Used by the widget for multi-currency price display and by agents for cross-currency deal valuation. No authentication required.
Rate limit: 100 requests per hour per IP. Rates are cached server-side — use the fetched_at field to determine freshness.
Return the current exchange rate from one currency to another.
| Parameter | Type | Description |
| from required | string | Source currency (ISO 4217, e.g. AUD) |
| to required | string | Target currency (ISO 4217, e.g. USD) |
Example
curl "https://api.salesbooth.com/v1/fx-rate?from=AUD&to=USD"
Response
{
"error": false,
"success": true,
"data": {
"from": "AUD",
"to": "USD",
"rate": 0.6512,
"provider": "open-exchange",
"fetched_at": "2026-03-15T10:00:00Z"
}
}
Machine-Readable Schemas
Public JSON Schema and state machine definitions for AI agents and integrators to understand deal structure programmatically. These endpoints require no authentication and are designed to be fetched and cached by agent frameworks.
No authentication required. Responses include Cache-Control headers — schemas change infrequently so aggressive caching is safe.
Rate limit: 30 requests per minute per IP.
Returns machine-readable state machine definitions for deals and contracts: all valid states, allowed transitions, and the conditions required for each transition. Use this to validate state changes before making API calls.
| Parameter | Type | Description |
| entity | string | deals or contracts (omit for both) |
Example
curl "https://api.salesbooth.com/v1/schema/state-machine?entity=deals"
Response (abbreviated)
{
"error": false,
"success": true,
"data": {
"schema_version": "1.0.0",
"entity_types": ["deals", "contracts"],
"deals": {
"states": ["draft", "open", "negotiating", "accepted", "signed", "closed", "cancelled"],
"transitions": [
{ "from": "draft", "to": "open", "action": "publish", "conditions": ["has_product", "has_customer"] },
{ "from": "negotiating", "to": "accepted", "action": "accept", "conditions": [] }
]
}
}
}
Returns a JSON Schema document describing the structure of deal terms. Agents use this to validate proposed terms before submitting a negotiation or deal creation request.
Example
curl "https://api.salesbooth.com/v1/schema/deal-terms"
Response (abbreviated)
{
"error": false,
"success": true,
"data": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "DealTerms",
"type": "object",
"properties": {
"price": { "type": "number", "minimum": 0 },
"currency": { "type": "string", "pattern": "^[A-Z]{3}$" },
"payment_terms": { "type": "string", "enum": ["immediate", "net_30", "net_60"] },
"discount_percent": { "type": "number", "minimum": 0, "maximum": 100 }
},
"required": ["price", "currency"]
}
}
Object Schemas
Human-readable field definitions for the core resource objects returned by the API.
Deal Object
| Field | Type | Description |
id | string | Unique identifier, prefix deal_ |
tenant_id | string | Tenant that owns the deal |
customer_id | string | Associated customer identifier |
title | string | Human-readable deal name (max 255 chars) |
description | string | Optional deal description |
status | enum | draft · in_progress · pending_signature · pending_payment · closed · cancelled |
deal_type | enum | one_time or recurring |
currency | string | ISO 4217 currency code (e.g. USD) |
tax_rate | decimal | Tax rate (stored as 0.1000 for 10%) |
subtotal | decimal | Sum of line items before tax — calculated, read-only |
total | decimal | Subtotal + tax — calculated, read-only |
line_items | array | Array of line item objects (see below) |
metadata | object | Arbitrary key-value pairs (max depth 3) |
version | integer | Optimistic lock version; pass in If-Match on PATCH |
created_at | ISO 8601 | Creation timestamp |
updated_at | ISO 8601 | Last modification timestamp |
Line Item Object
{
"id": "item_xxxxx",
"deal_id": "deal_xxxxx",
"product_id": "prod_xxxxx",
"quantity": 2,
"unit_price": "499.00",
"discount": "10.00",
"line_total": "888.20"
}
Customer Object
| Field | Type | Description |
id | string | Unique identifier, prefix cust_ |
name | string | Full name (encrypted at rest) |
email | string | Email address (encrypted at rest) |
phone | string | Phone number (encrypted at rest, optional) |
company | string | Company or organisation name |
metadata | object | Arbitrary key-value pairs |
created_at | ISO 8601 | Creation timestamp |
updated_at | ISO 8601 | Last modification timestamp |
Product Object
| Field | Type | Description |
id | string | Unique identifier, prefix prod_ |
name | string | Product display name |
description | string | Product description |
price | decimal | Base price (subject to configured pricing rules) |
type | enum | service · physical · digital · subscription |
status | enum | active or archived |
sku | string | Optional stock-keeping unit identifier |
currency | string | ISO 4217 currency for this product’s base price |
metadata | object | Arbitrary key-value pairs |
created_at | ISO 8601 | Creation timestamp |
Budget Management
Configure monthly spending limits and alert thresholds for API usage. When the monthly limit is reached, the API returns 402 Payment Required until the next billing cycle or the limit is raised. Requires session (cookie) authentication.
Retrieve current budget settings and the month-to-date spend.
Example
curl https://api.salesbooth.com/v1/budget \
-H "Cookie: session=..."
Response
{
"error": false,
"success": true,
"data": {
"budget": {
"monthly_limit": 1000.00,
"monthly_limit_cents": 100000,
"alert_at_percent": [80, 100],
"current_spend": 612.40,
"current_spend_cents": 61240,
"percent_used": 61.2
}
}
}
Update the monthly budget limit and alert thresholds.
| Field | Type | Description |
| monthly_limit required | number | Monthly spend cap in USD. Set to 0 to disable the cap. |
| alert_at_percent | array | Percentage thresholds that trigger email alerts (e.g. [80, 100]) |
Example
curl -X POST https://api.salesbooth.com/v1/budget \
-H "Cookie: session=..." \
-H "Content-Type: application/json" \
-d '{ "monthly_limit": 500.00, "alert_at_percent": [75, 90, 100] }'
USDC Payment Rail
Manage USDC prepaid balances for AI agent accounts on Base L2. Agents can fund their account via Coinbase Commerce and then spend USDC against deal credits — no Stripe required. USDC balances are separate from the standard credit system.
Required scope: billing:read (balance & transactions), billing:write (create charge, set wallet)
Network: Base L2 (Coinbase). Minimum deposit: 1 USDC.
Get the current USDC balance and agent wallet summary.
Example
curl https://api.salesbooth.com/v1/usdc?action=balance \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{
"error": false,
"success": true,
"data": {
"balance_usdc": 42.50,
"wallet_address": "0xabc...def",
"network": "base",
"agent_summary": { "total_spent": 157.50, "total_deposited": 200.00 }
}
}
Retrieve paginated USDC transaction history.
| Parameter | Type | Description |
| page | integer | Page number (default: 1) |
| per_page | integer | Results per page (default: 20, max: 100) |
Create a Coinbase Commerce charge to deposit USDC into the agent’s balance. Returns a hosted checkout URL to redirect the payer to.
| Field | Type | Description |
| amount required | number | Amount in USDC to deposit (minimum: 1) |
Example
curl -X POST https://api.salesbooth.com/v1/usdc?action=create-charge \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{ "amount": 50.00 }'
Register an on-chain wallet address for the agent account. Used for identity verification and optional direct settlement.
| Field | Type | Description |
| wallet_address required | string | EVM-compatible wallet address (0x...) |
Fraud Signals
Review and manage fraud detection signals. Signals are generated automatically during deal and payment events and accumulate a severity score that may trigger trust-level demotions. This API allows merchants to list, resolve, and manually trigger evaluations.
Required scope: trust:read (GET), trust:write (POST resolve/evaluate)
List fraud signals with optional filtering. Returns signal severity, cumulative 24h scores, and whether demotion thresholds have been crossed.
| Parameter | Type | Description |
| unresolved | string | Show only unresolved signals: 1 or 0 |
| limit | integer | Max results (default: 25, max: 100) |
| offset | integer | Pagination offset |
Example
curl https://api.salesbooth.com/v1/fraud-signals?unresolved=1 \
-H "Authorization: Bearer sb_test_example_key_do_not_use"
Retrieve trust-level demotion history triggered by accumulated fraud signals.
Mark a fraud signal as resolved after investigation. Resolved signals are excluded from future severity calculations.
| Field | Type | Description |
| signal_id required | string | Signal to resolve |
Manually trigger a fraud evaluation run. Useful after resolving signals to confirm the tenant’s risk score has improved before requesting a trust-level review.
Session Auth
JSON-based authentication for the admin panel and SPA clients. Uses secure HttpOnly cookies; not intended for API key–based integrations.
Returns the current session status, authenticated user, and accessible workspaces. Returns authenticated: false if no active session.
Authenticate with email and password. Sets a session cookie on success. Use action=select-tenant to switch to a specific workspace after login.
| Field | Type | Description |
| email required | string | User email address |
| password required | string | User password |
| remember | boolean | Persist session across browser restarts (30-day remember-me cookie) |
Example
curl -X POST https://api.salesbooth.com/v1/auth \
-H "Content-Type: application/json" \
-c cookies.txt \
-d '{"email": "user@example.com", "password": "secret"}'
Logout: destroy the current session and clear the session cookie. Returns 200 OK even if no active session exists.
User Profile
Manage the authenticated user’s personal profile fields. Requires an active session.
Retrieve the current user’s profile: first name, last name, email, and phone.
Response (200)
{
"error": false,
"data": {
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@example.com",
"phone": "+1-555-0100"
}
}
Update the current user’s profile. Send only the fields to change.
| Field | Type | Description |
| first_name | string | First name |
| last_name | string | Last name |
| phone | string | Mobile phone number |
Change the current user’s password. Requires an active session. The current password must be provided for verification.
| Field | Type | Description |
| old_password required | string | The user’s current password for verification |
| new_password required | string | The new password (minimum 8 characters) |
Example
curl -X POST "https://api.salesbooth.com/v1/profile?action=change-password" \
-H "Cookie: session=..." \
-H "Content-Type: application/json" \
-d '{
"old_password": "oldPassword123",
"new_password": "newSecurePassword456"
}'
Preferences
Store user and workspace-level UI preferences. Preferences are keyed by scope: user (global per user) or tenant (per workspace).
Retrieve preferences for the given scope. user scope returns global preferences (language, theme). tenant scope returns workspace preferences (recommendations_dismissed).
Update preferences for the given scope. Only whitelisted keys are accepted: language, theme for user scope; recommendations_dismissed for tenant scope.
Example
curl -X PATCH https://api.salesbooth.com/v1/preferences?scope=user \
-H "Content-Type: application/json" \
-d '{"language": "en", "theme": "dark"}'
Display Mode
Control whether the app renders in PWA standalone mode or standard browser mode. Called automatically by the front-end on load; you can also set it explicitly for testing.
Returns the current display mode setting: standalone, browser, or auto.
Set the display mode. Use auto to clear any forced mode and return to browser-detection.
| Field | Type | Description |
| mode required | string | standalone, browser, or auto |
Business Profile
The business profile provides a natural-language description of the tenant’s business, used as context for AI website generation. Stored in tenant_settings.
Retrieve the current business profile for the authenticated workspace.
Save or update the business profile. The profile is a free-form description used by AI website generation and other AI features.
| Field | Type | Description |
| business_name | string | Trading name |
| description | string | Detailed description of the business, products, and target market |
| industry | string | Industry category |
| target_market | string | Intended customer segment |
Analytics Settings
Manage analytics and session replay tracking preferences for the current workspace. Settings are stored in tenants.metadata.
Returns the current analytics tracking configuration including toggles for mouse recording, heatmaps, and custom CSS block selectors to exclude from recording.
Update analytics settings. Send only the fields to change.
| Field | Type | Description |
| enabled | boolean | Master toggle for analytics collection |
| record_mouse | boolean | Record mouse movements in session replays |
| block_selector | string | CSS selector for elements to exclude from recording (e.g. .pii-field) |
Tenant Settings
Read and update workspace-level settings: business details, branding, and operational configuration. Direct column fields are stored in the tenants table; extended fields (industry, tax_id, primary_color, currency) are stored in tenants.metadata.
Returns all settings for the current workspace including name, subdomain, industry, default currency, branding colours, and tax configuration.
Update workspace settings. Send only the fields to change.
| Field | Type | Description |
| name | string | Workspace display name |
| industry | string | Industry category |
| default_currency | string | ISO 4217 code (e.g. USD) |
| primary_color | string | Brand colour hex (e.g. #635bff) |
| default_tax_rate | string | Default tax rate as decimal (e.g. 0.10 for 10%) |
| custom_domain | string | Custom domain for the hosted website |
Communication Channels
Manage the tenant’s outbound communication settings: phone number (Twilio), sender email address, and sender name. Used when sending deal notifications and quotes.
Returns the current channel configuration: phone number, from email, and sender name.
Save communication channel settings.
| Field | Type | Description |
| phone_number | string | Twilio phone number in E.164 format (e.g. +15550001234) |
| from_email | string | Sender email address for outbound messages |
| from_name | string | Sender display name |
Switch Workspace
Switch the active workspace for the current session. Users with access to multiple workspaces can switch without re-authenticating.
Switch the session to a different workspace. The user must already have access to the target workspace.
| Field | Type | Description |
| tenant_id required | string | Target workspace ID |
Tenant Context
Manage per-tab workspace context. Allows each browser tab to operate in a different workspace without affecting other tabs. Context is stored in the session keyed by tab ID (sent via X-Tab-ID header).
Returns the workspace ID associated with the current tab. Requires the X-Tab-ID header.
Set or clear the workspace context for a specific tab. Pass tenant_id: null to clear the tab-specific context and fall back to the session default.
| Field | Type | Description |
| tab_id required | string | Browser tab identifier |
| tenant_id | string|null | Workspace ID to bind to this tab, or null to clear |
Workspace List
Returns all workspaces accessible to the authenticated user. Multi-workspace users use this to populate the workspace switcher.
Returns an array of workspace objects: ID, name, slug, logo, region, regional endpoint, sandbox flag, current flag, and the user’s role in each.
Response (200)
{
"error": false,
"data": [
{
"tenant_id": "au_tenant_abc123",
"name": "Acme Corp",
"slug": "acme-corp",
"logo_url": null,
"role": "owner",
"is_current": true,
"is_sandbox": false,
"region": "au",
"regional_endpoint": "https://api-au.salesbooth.com"
}
]
}
Health Check
Public endpoint for monitoring and infrastructure probes. No authentication required. Rate limited to 10 requests per minute per IP.
Full health report including database, cache, and queue status. Always returns HTTP 200 — check status in the body.
| Parameter | Description |
| type | liveness — minimal PHP-FPM alive check (use for Nginx upstream); readiness — all dependencies healthy (use for load balancer routing); omit for full report |
Response (200)
{
"status": "healthy",
"checks": {
"database": { "status": "ok", "latency_ms": 2 },
"redis": { "status": "ok" },
"queue": { "status": "ok", "pending": 0 }
},
"timestamp": "2026-03-18T10:00:00Z"
}
Usage Reporting
Access AI service usage logs and cost summaries for the current workspace. Useful for cost allocation, auditing, and charting monthly spend trends.
Paginated log of API service calls with per-entry cost and token counts.
| Parameter | Description |
| service | Filter by service name (e.g. claude, openai) |
| start_date | ISO 8601 start date |
| end_date | ISO 8601 end date |
| limit | Max results (default: 100, max: 1000) |
| offset | Pagination offset |
Monthly usage summary: total cost, token counts, and breakdown by service.
Daily usage breakdown for charting — returns an array of {date, cost, tokens} objects for the last 30 days.
Cache Administration
Inspect and flush the Redis cache for the current workspace. Requires the admin scope. Cache keys are namespaced by sb:{tenant_id}: to prevent cross-tenant access.
Returns cache statistics: key count, memory usage, hit/miss ratio, and Redis version.
Flush all cache entries for this workspace. Use the prefix parameter to invalidate only a subset.
| Parameter | Description |
| prefix | Cache key prefix to invalidate (e.g. products). Omit to flush all workspace keys. |
Deal Participants
Manage multi-party deal collaboration. Participants are agents or humans invited to a deal with specific roles, permission scopes, and revenue-share allocations. Supported roles: primary_agent, co_agent, observer.
List all participants for a deal. Use action=settlements to retrieve final revenue-share settlement records.
| Parameter | Description |
| deal_id required | Deal identifier |
| action | settlements — return settlement records for a completed deal |
Invite a participant, or perform lifecycle actions (accept, complete). Send X-Delegation-ID header if acting on behalf of an agent.
| Field | Type | Description |
| agent_id | string | Agent identifier to invite |
| role required | string | primary_agent, co_agent, or observer |
| revenue_share | number | Revenue share percentage (0–100) |
| scope | string[] | Permission scopes granted to this participant |
Example
curl -X POST "https://api.salesbooth.com/v1/deal-participants?deal_id=deal_abc" \
-H "Authorization: Bearer sb_test_example_key_do_not_use" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "agent_xyz",
"role": "co_agent",
"revenue_share": 25,
"scope": ["deals:read", "agent:negotiate"]
}'
Update a participant’s role, scope, or revenue-share allocation.
Remove (withdraw) a participant from a deal. Only possible while the deal is in draft or in_progress status.
Negotiations Dashboard
Internal merchant-facing endpoint providing an aggregated view of active negotiations, auto-accept thresholds, and deal management actions. Requires an active session.
Returns dashboard stats and a list of active negotiations with latest proposals.
| Parameter | Description |
| view | dashboard (default) — stats + list; detail — single deal negotiation detail (requires deal_id) |
| deal_id | Deal ID when view=detail |
Perform a negotiation action. Supported actions: accept, counter, reject, update_threshold.
| Parameter | Description |
| action required | accept — accept latest proposal; counter — send counter-offer; reject — reject; update_threshold — set auto-accept percentage |
Dashboard Statistics
Consolidated endpoint returning all dashboard data in a single request. Cached for 2 minutes. Requires deals:read scope.
Returns entity counts, pipeline analytics, revenue time-series (last 30 days), and attention items (expiring deals, stale deals, expiring contracts).
Response (200)
{
"error": false,
"data": {
"counts": { "customers": 142, "deals": 38, "products": 24, "contracts": 17 },
"pipeline": { "total_value": 285000, "avg_deal_size": 7500, "win_rate": 0.68 },
"revenue_series": [{ "date": "2026-03-01", "total": 12400, "count": 3 }],
"attention": {
"expiring_deals": [],
"expiring_contracts": [],
"stale_deals": []
}
}
}
Site Blocks
Manage reusable content blocks for the website builder. Blocks can be shared across pages within a site and referenced by slug. Requires session authentication.
List all blocks for the workspace, optionally filtered by site.
| Parameter | Description |
| site_id | Filter blocks by site |
| id | Retrieve a single block by ID |
Create a new block, or use action=update_status to publish/unpublish a block.
| Field | Type | Description |
| site_id required | string | Parent site identifier |
| name required | string | Block display name |
| type | string | Block type (e.g. hero, testimonial, cta) |
| content | string | HTML or structured content for the block |
Update a block’s name, type, or content.
Permanently delete a block. Returns 409 if the block is still referenced by active pages.
AI Website Generation
Generate full websites, page templates, or individual pages using AI. Uses the tenant’s business profile and product catalog as context. Long-running — set client timeouts to at least 120 seconds.
Generate a complete multi-page website based on the business profile and product catalog. Creates pages in the active site.
| Parameter | Description |
| action | template — generate CSS, header, and footer only; page — generate or regenerate a single page; omit for full site generation |
Domain Availability
Check whether a domain name is available for registration. Powered by the Dreamscape API.
Check domain availability and get a registration price if available.
| Field | Type | Description |
| domain required | string | Domain name to check (e.g. example.com) |
Response (200)
{
"error": false,
"data": { "available": true, "price": "12.99" }
}
Get the server IP address for DNS A-record configuration when setting up a custom domain.
Response (200)
{
"error": false,
"data": { "ip": "203.0.113.42" }
}
Domain Registration
Register a domain name and associate it with the current workspace’s website. Charges are applied to the workspace credit balance.
Register the domain and configure DNS to point to the workspace website. Requires available credits.
| Field | Type | Description |
| domain required | string | Domain to register (must be verified as available first) |
| site_id | string | Site to associate the domain with |
Activity Stream (SSE)
Real-time activity feed using Server-Sent Events. Polls the activity_feed table every 2 seconds and streams new events to the client. Use the browser’s EventSource API for automatic reconnection.
Opens a persistent SSE connection. Events are sent as JSON with id, event type, and data fields. The connection emits a heartbeat event every 30 seconds.
| Parameter | Description |
| last_event_id | Resume from this event ID (also read from Last-Event-ID header on reconnect) |
Example (JavaScript)
const es = new EventSource('/api/v1/activity-stream');
es.addEventListener('activity', e => {
const event = JSON.parse(e.data);
console.log(event.type, event.entity_id);
});
es.addEventListener('heartbeat', () => console.log('alive'));
Session Replays
Manage recorded session replay data. Replay events are collected via the Event Collection endpoint and stored as JSONL files. Use the Analytics Settings endpoint to configure recording preferences.
List session recordings for the current workspace, ordered by most recent activity. Supports pagination via limit and offset.
| Parameter | Type | Description |
| limit | integer | Max recordings to return (1–200, default 50) |
| offset | integer | Pagination offset (default 0) |
200
401
Permanently delete a session recording from the database and disk. Returns 404 if the session is not found or does not belong to the current workspace.
| Parameter | Description |
| session_id required | Session replay identifier |
Event Collection
Public endpoint that accepts session replay and analytics events from the SDK. No authentication required — uses a publishable key for workspace routing. Called automatically by the analytics SDK.
Store a batch of session replay or analytics events. Events are stored as JSONL organised by domain and session ID.
| Field | Type | Description |
| session_id required | string | Unique session identifier (generated client-side) |
| events required | array | Array of event objects with type, timestamp, and data |
| publishable_key required | string | Workspace publishable key for routing |
Job Queue
Monitor and manage the background job queue. Supports inspecting queue statistics, checking individual job status, viewing dead-lettered jobs, retrying failed jobs, and purging old records. Requires queue:read or queue:write scope.
Get queue statistics: pending, processing, completed, and dead-lettered job counts.
Get detailed status for a specific job: state, attempts, last error, and timestamps.
List dead-lettered (permanently failed) jobs. Returns up to 100 entries per page.
Re-enqueue a dead-lettered job. Requires queue:write scope.
Purge old completed or dead-lettered jobs. Use action=purge-dead-letter to purge only the dead letter queue.
Agent Registry
Same-tenant agent peer discovery for multi-agent coordination. Enables agents to discover peer and child agents in the same workspace, query activity summaries, and detect product contention before starting duplicate negotiations. Requires agent:discover scope.
Privacy: Responses are summary-level only to prevent information leakage between competing agents. Agents may only see their peers and children — never ancestors in the delegation hierarchy.
Discover active agents or check for product contention.
| Parameter | Description |
| action required | list_agents — list active peer agents; agent_activity — activity summary for an agent; check_contention — check if a product is already being negotiated |
| product_id | Product ID to check for contention (when action=check_contention) |
| agent_id | Agent ID to query activity for (when action=agent_activity) |
AI Chat Assistant
Conversational AI assistant for managing customers, products, deals, and viewing business data. Supports streaming responses. Powered by Claude with extended thinking for complex queries.
Send a message to the AI assistant. Supports streaming via Server-Sent Events when stream=true.
| Field | Type | Description |
| messages required | array | Chat history: array of {role: "user"|"assistant", content: string} |
| stream | boolean | Enable SSE streaming (default: false) |
| thinking | boolean | Enable extended thinking for complex queries (default: false) |
Text to Speech
Convert text to natural-sounding speech using OpenAI TTS. Supports streaming audio for low-latency playback. Requires a configured OpenAI API key.
Convert text to MP3 audio. Use stream=true for raw audio streaming (faster); the default returns base64-encoded audio in JSON.
| Field | Type | Description |
| text required | string | Text to convert (max 4096 characters) |
| voice | string | Voice: nova (default), alloy, echo, fable, onyx, shimmer |
| stream | boolean | Stream raw MP3 bytes directly (sets Content-Type: audio/mpeg) |
Realtime Voice Session
Create ephemeral tokens for browser-side WebSocket connections to the OpenAI Realtime API. Keeps the OpenAI API key secure on the server. Tokens expire after 60 seconds.
Returns a short-lived ephemeral token for the client to connect directly to OpenAI’s Realtime API WebSocket.
| Field | Type | Description |
| model | string | OpenAI Realtime model (default: gpt-4o-realtime-preview) |
| voice | string | TTS voice for the realtime session (default: nova) |
Response (200)
{
"error": false,
"data": {
"client_secret": { "value": "ek_...", "expires_at": 1742000060 },
"session_id": "sess_abc123"
}
}
Realtime Function Calls
Execute function calls originating from the OpenAI Realtime API voice assistant. The browser forwards function call requests here; the server executes them using full service-layer access and returns results.
Execute a named function call. Supported functions include customer search, deal listing, product lookup, contract status, and more — matching the same tool surface as the chat assistant.
| Field | Type | Description |
| function_name required | string | Name of the function to execute (e.g. list_customers, get_deal) |
| arguments required | object | Function arguments as a JSON object |
Realtime Usage Reporting
Client-side token usage reporting for Realtime API voice sessions. Because the browser connects directly to OpenAI via WebSocket, the server cannot observe usage; the client reports it here for billing and analytics tracking.
Record token usage from a completed realtime voice session.
| Field | Type | Description |
| session_id required | string | Realtime session identifier |
| input_tokens | integer | Number of input tokens consumed |
| output_tokens | integer | Number of output tokens generated |
| duration_seconds | number | Session duration in seconds |
CSV Import
Three-step CSV import wizard for bulk-loading customers and products. Step 1 parses the file and auto-detects column mappings. Step 2 validates the mapped data and returns row-level errors. Step 3 executes the import inside a database transaction.
Parse a CSV file (JSON body). Returns detected headers, sample rows, and auto-suggested column mappings.
| Field | Type | Description |
| csv_content required | string | CSV file content as a string |
| entity_type required | string | customers or products |
Validate column-mapped data. Returns per-row errors without making any changes.
Execute the import inside a transaction. Returns counts of created, updated, and skipped records.
Sandbox Toggle
Switch the dashboard between live mode and sandbox (test) mode. Only available for session-authenticated users — API key requests cannot change the sandbox mode. Sandbox mode uses Stripe’s test keys and does not process real payments.
Returns the current mode: test (sandbox active) or live.
Switch between sandbox and live mode.
| Field | Type | Description |
| mode required | string | test for sandbox, live for production |
Payment Intent
Create a Stripe PaymentIntent for a deal’s deposit or full amount. Called by the <salesbooth-deal> embed widget when the buyer reaches the payment step. Requires deals:write scope.
Create a Stripe PaymentIntent. Returns a client_secret for use with Stripe.js to complete payment on the client.
| Field | Type | Description |
| deal_id required | string | Deal to create a PaymentIntent for |
| amount | number | Override amount in the deal’s currency (omit to use deal total) |
Response (200)
{
"error": false,
"data": {
"client_secret": "pi_xxx_secret_yyy",
"payment_intent_id": "pi_xxx",
"amount": 1499.00,
"currency": "usd"
}
}
Onboarding
Complete the new-user onboarding wizard or create an additional workspace for an existing user. No authentication required for new users; existing users must be authenticated.
Complete onboarding: creates the user account, tenant workspace, and initial products in a single transaction. Returns a session cookie for immediate login.
| Field | Type | Description |
| first_name required | string | User first name |
| last_name required | string | User last name |
| email required | string | User email address |
| password required | string | Password (min 8 characters) |
| business_name | string | Business or workspace name (required for human accounts) |
| industry | string | Business industry (required for human accounts) |
| services | array | List of services offered (required for human accounts). Each item: {name, description, price_min, price_max} |
| deposit_percentage | number | Default deposit percentage (0–100) |
| phone | string | Business phone number |
| website | string | Business website URL |
| country | string | Two-letter country code (default: US) |
| region | string | Data residency region: au, eu, or us |
| account_type | string | Account type: human (default) or agent. Agent accounts skip business field validation. |
Create an additional workspace for an already-authenticated user. The new workspace is automatically linked to the user’s account.
Credential Verification
Public endpoint for verifying the signature and status of Salesbooth verifiable credentials. No authentication required — any third party (lenders, insurers, regulators, counterparties) can verify a credential’s authenticity.
Verify a credential: checks the Ed25519 signature, revocation status, and expiry. Returns valid: true if the credential is authentic and has not been revoked.
| Field | Type | Description |
| credential required | object | The verifiable credential JSON object (as issued by Salesbooth) |
Response (200)
{
"error": false,
"data": {
"valid": true,
"credential_id": "vc_abc123",
"deal_id": "deal_xyz",
"issued_at": "2026-03-01T10:00:00Z",
"expires_at": "2027-03-01T10:00:00Z",
"revoked": false
}
}
Internal Endpoints
The following endpoints are infrastructure-facing or webhook receivers. They are listed here for completeness but are not intended for direct use by API consumers. Do not call these endpoints from client integrations.
API discovery endpoint. Returns a list of available API routes, authentication methods, agent integration details, and a link to the OpenAPI specification.
No authentication required. Not required for normal integration — use the
OpenAPI spec instead.
Example
curl https://api.salesbooth.com/v1/api
Response (200)
{
"error": false,
"data": {
"name": "Salesbooth API",
"version": "1.0.0",
"base_url": "https://api.salesbooth.com/v1",
"documentation": "https://salesbooth.com/docs",
"openapi_spec": "https://salesbooth.com/api/openapi.json",
"endpoints": { "deals": { ... }, "customers": { ... } }
}
}
Receives browser Content Security Policy violation reports. This is the target of the report-uri CSP directive sent in all page responses. No authentication required. Accepts both application/csp-report and application/json content types. Rate limited at 30 req/min per IP.
Request body (browser-sent automatically)
{
"csp-report": {
"document-uri": "https://salesbooth.com/deals",
"violated-directive": "script-src",
"blocked-uri": "https://evil.example.com/script.js"
}
}
Receives inbound email events from SendGrid or Mailgun (bounces, complaints, delivery confirmations, and inbound messages). Validated via a provider-specific token. No authentication required — configure your email provider to POST events to this URL.
Configure in your email provider
Webhook URL: https://api.salesbooth.com/v1/email-webhook
Content-Type: multipart/form-data (SendGrid) or application/json (Mailgun)
Receives and processes incoming Stripe webhook events: payment intents, subscription lifecycle, invoice events, and dispute notifications. Signature-verified via the Stripe-Signature header against STRIPE_WEBHOOK_SECRET. No authentication required — configure in your Stripe dashboard.
| Header | Description |
| Stripe-Signature required | Stripe-provided HMAC signature for payload verification |
Configure in Stripe Dashboard
Webhook URL: https://api.salesbooth.com/v1/stripe-webhook
Events: payment_intent.*, invoice.*, customer.subscription.*, charge.dispute.*
Returns Twilio configuration status and communication history. No credentials are exposed. Requires session authentication.
| Parameter | Description |
| action | settings (default) for configuration status; history for communication history log |
Save Twilio credentials or send an outbound SMS, voice call, or email. Called by the Salesbooth dashboard communications settings page. Requires session authentication.
| Field | Description |
| action required | settings to save credentials; sms to send SMS; call to initiate voice call; email to send email |
| to | Recipient phone number (E.164 format) or email address, depending on action |
| message | Message body for SMS or email content |
| account_sid | Twilio account SID (required for action=settings) |
| auth_token | Twilio auth token (required for action=settings) |
Receives inbound SMS messages, voice call status callbacks, and delivery status updates from Twilio. Signature-verified via Twilio’s X-Twilio-Signature header. No authentication required — configure in your Twilio console.
| Parameter | Description |
| type | Event type: sms (inbound message), voice (call status), status (delivery callback) |
Configure in Twilio Console
SMS Webhook URL: https://api.salesbooth.com/v1/twilio-webhook?type=sms
Voice Webhook URL: https://api.salesbooth.com/v1/twilio-webhook?type=voice
Changelog
Salesbooth is pre-launch. The public changelog will start on the day the product goes live. Until then this section is intentionally empty.