AI agent commerce

Salesbooth is the commerce layer for AI agents

Expose products, pricing, negotiation rules, contracts, payments, permissions, and trust to websites, humans, and autonomous agents through one deal API.

What is Salesbooth?

Salesbooth lets businesses expose their products, pricing, contracts, approvals, and payment flows to humans, websites, and AI agents through one governed deal platform.

The simple test: Can I let an AI agent sell my products, negotiate terms, create a contract, and take payment without giving it unlimited authority? Salesbooth is built so the answer can be yes.

For SaaS and subscription businesses

Let prospects configure seats, negotiate allowed discounts, sign terms, and start billing.

For marketplaces and services

Coordinate quotes, bookings, deposits, approvals, participants, and fulfillment workflows.

For AI builders

Give ChatGPT, AI assistant, or your own agent controlled commerce tools instead of brittle custom REST glue.

Start with the outcome

Most teams should choose one of these paths before opening the endpoint reference.

1. Embed a sales widget on your website

Use the browser-safe widget when the buyer is on your site and you want a complete guided commerce surface.

  • Show product and configuration options.
  • Capture the customer and saved configuration.
  • Create a quote or deal and collect payment.

2. Give an AI agent permission to sell

Use Agent Commerce when an AI seller or buyer needs to discover offers, negotiate, and complete deals safely.

  • Discover products and offers through controlled tools.
  • Negotiate inside discount, spend, trust, and approval limits.
  • Create deals, send contracts, and request payment.

3. Run deal infrastructure through an API

Use the Core Commerce API when your app owns the interface and Salesbooth is the deal system underneath.

  • Manage customers, products, deals, contracts, and payments.
  • Listen to webhooks and real-time deal events.
  • Keep an audit trail for every commercial action.

Agent commerce in plain English

Connect ChatGPT, Claude, or your own agent to Salesbooth. Your agent can discover offers, negotiate, create deals, check rules, and complete purchases through controlled tools.

Agents cannot spend unlimited money. You control what they can see, negotiate, sign, and spend with API scopes, CORS restrictions, delegation budgets, trust levels, approval thresholds, and audit logs.

MCP turns the platform into tools. Salesbooth exposes 192 MCP tools across 28 categories so agents can work with products, deals, contracts, payments, subscriptions, and approvals without hand-coded REST calls for every action.

Plain-English agent examples

Sell within a cap

Create an agent that can sell subscriptions up to $500/month without approval.

Negotiate, but not sign

Allow a purchasing agent to negotiate commercial terms but require a human before signature.

Discover before payment

Let agents discover deals and build quotes, then require approval before money moves.

End-to-end demo: 20 seats bought by an AI agent

An AI buyer wants 20 seats of software. Salesbooth lets the agent discover the offer, negotiate a discount, request approval when needed, sign the contract, and pay through one governed flow.

1. Discover the offer

The agent calls MCP tools such as discover_deals or list_products to find a subscription product that can be sold to the buyer.

2. Price 20 seats

It checks configuration and volume pricing with calculate_pricing or the Core API before proposing terms.

3. Negotiate inside limits

The agent uses negotiate_terms, but discount caps and delegation budgets decide whether the offer can continue automatically.

4. Create the deal

Salesbooth creates the buyer, then uses create_deal and add_deal_item so the quote becomes a trackable deal.

5. Get approval if required

If the deal exceeds a threshold, the workflow waits for workflow_approve_step or escalates through the approval queue.

6. Sign and pay

The approved deal becomes a contract with create_contract_from_deal, then payment is collected with create_payment_intent or a payment link.

Overview

The Salesbooth API is a RESTful API that uses application/json by default for both requests and responses. Start with the outcome above, then use the smallest spec that matches your integration.

If you are integrating for the first time, start with the smaller audience-specific specs. Admin and internal dashboard APIs are not published publicly.

Start hereUse whenSpec
Core Commerce APICustomers, products, deals, contracts, payments, webhooks, and commerce schemas/api/core-openapi.json
Widget APIWidget config, saved configs, pricing previews, validation, analytics, and bookings/api/widget-openapi.json
Agent APITool calling, negotiation, delegation, trust, federation, and agent workflows/api/agent-openapi.json
Legacy Public AliasYou still depend on the broader compatibility document that mirrors the full documented public API surface without admin or internal routes/api/public-openapi.json
Public Compatibility APIYou want the default public OpenAPI document for customers, deals, payments, widgets, and other external integration surfaces without admin or internal routes/api/openapi.json

OpenAPI spec endpoints

These public spec aliases return raw OpenAPI JSON rather than the standard API envelope, making them suitable for code generation, agent tool discovery, and Try-it clients.

GET /api/v1/public-openapi.json
Return the public compatibility OpenAPI view that combines the core commerce and embedded widget surfaces. No authentication required.
Example
curl https://api.salesbooth.com/v1/public-openapi.json
Response: HTTP 200 raw OpenAPI 3.1 JSON document. Common errors: 404, 405, and 429.
GET /api/v1/agent-openapi.json
Return the filtered AI agent API specification for tools, MCP, trust, delegations, workflows, negotiations, and agent-facing commerce routes. No authentication required.
Example
curl https://api.salesbooth.com/v1/agent-openapi.json
Response: HTTP 200 raw OpenAPI JSON. Common errors: 404, 405, and 429.
GET /api/v1/core-openapi.json
Return the filtered core commerce API specification for customers, products, deals, contracts, payments, and commerce schemas. No authentication required.
Example
curl https://api.salesbooth.com/v1/core-openapi.json
Response: HTTP 200 raw OpenAPI JSON. Common errors: 404, 405, and 429.
GET /api/v1/widget-openapi.json
Return the filtered embedded widget API specification for configuration, validation, pricing, bookings, analytics, and saved configuration flows. No authentication required.
Example
curl https://api.salesbooth.com/v1/widget-openapi.json
Response: HTTP 200 raw OpenAPI JSON. Common errors: 404, 405, and 429.

Build This in 30 Minutes

Build a server-side deal flow: Create customer → create deal → add products → send contract → collect payment.

Build an embedded commerce flow: Embed widget → save config → convert to deal.

Build an agent-first commerce flow: Agent discovers offer → negotiates → signs → pays.

Exceptions are documented on the affected endpoint cards: multipart/form-data uploads, text/event-stream event streams, text/csv and application/x-ndjson deal exports, text/csv audit exports, and text/html invoice downloads.

Base URL
https://api.salesbooth.com/v1/
API Discovery — GET /api
{ "error": false, "success": true, "data": { "name": "Salesbooth API", "version": "1.20.2", "base_url": "https://api.salesbooth.com/v1", "documentation": "https://salesbooth.com/docs", "openapi_spec": "https://api.salesbooth.com/openapi.json" } }

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": { "field": "name", "issue": "required" } }

Authentication

Authenticate secret API requests with an API key sent as a Bearer token or via the X-API-Key header. Secret keys (sb_live_{region}_*, sb_test_{region}_*) are not accepted in the ?api_key= query parameter.

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....

PrefixTypeEnvironmentNotes
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 an api_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 not supported. Query parameters appear in server logs, browser history, and referrer headers — use header-based authentication instead.

Note: Publishable keys (sb_pub_{region}_*) used by widget public endpoints and other documented public flows (for example /api/v1/widget-config, /api/v1/widget-intelligence, /api/v1/widget-bookings, /api/v1/ab-tests/resolve, widget analytics beacons, and SSE endpoints) are separate endpoint-specific exceptions. Those flows may accept ?api_key= in their own public/browser-oriented auth paths, independent of the standard secret-key authentication flow.

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.

ScopeDescription
*Full access — all resources, all operations
*:readRead-only access to all resources
deals:readRead deals, line items, and deal audit trail
deals:writeCreate, update, and manage deals and deal templates
deals:signSign and countersign deals
customers:readRead customer records and customer audit trail
customers:writeCreate and update customers
products:readRead products, pricing, and product audit trail
products:writeCreate and update products
contracts:readRead contracts and contract audit trail
contracts:writeCreate, sign, and manage contracts
webhooks:readList webhooks and delivery history
webhooks:writeRegister and manage webhooks
agent:*Full agent access — discover, negotiate, and execute deals
agent:discoverDiscover available deals and tenant catalogue
agent:negotiateNegotiate deal terms on behalf of a buyer
agent:executeExecute and accept deals
intelligence:readRead intelligence configuration and AI settings
intelligence:writeUpdate intelligence configuration and AI settings
billing:readRead credit balance and ledger
billing:writeTop up credits and manage billing
trust:readRead trust level and progress metrics
trust:writeWrite trust signals and submit fraud reports
staff:readRead staff members and availability
staff:writeCreate and update staff members
team:readRead team members
team:writeInvite, update, and remove team members
bookings:readRead bookings and appointments
bookings:writeCreate and manage bookings
audit:exportExport audit trail compliance packages
sandbox:readRead sandbox environment status
sandbox:writeReset, seed, and simulate webhooks in sandbox mode
delegations:readRead agent delegations
delegations:writeCreate and manage agent delegations
activity:readRead activity feed and stream events
activity:writeWrite activity entries
search:readSearch across deals, customers, and products
widgets:readRead widget configurations and validate headless sessions

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-hour limit (default: 1,000 req/hr, sliding window). Agent keys receive a trust-level multiplier on top of the configured limit:

Trust LevelMultiplierEffective Limit (default key)
L0 — Untrusted0.5×500 req/hr
L1 — Provisional1.0×1,000 req/hr
L2 — Established2.0×2,000 req/hr
L3 — Trusted5.0×5,000 req/hr
L4 — Verified Partner10.0×10,000 req/hr

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-hour limit, refilled at keyLimit/3600 tokens per second (≈0.278 tok/s for the 1,000 req/hr default).

Tier 2 — Per-IP Limit

Request TypeLimitWindow
Authenticated requests5,000 req/hrSliding hourly window
Unauthenticated requests100 req/hrSliding 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

HeaderDescription
X-RateLimit-LimitLimit for the tier that was checked (after trust multiplier)
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp when the window resets
X-RateLimit-PolicyWhich tier triggered the limit: global, ip, key, endpoint, or burst
X-Trust-LevelAgent key trust level (0–4), included when a trust multiplier applied
X-RateLimit-MultiplierTrust multiplier applied to the key limit (e.g. 2.0)
Retry-AfterSeconds to wait before retrying (present on 429 and 503)

HTTP Status Codes

StatusMeaningWhen to retry
429Per-key or per-IP limit exceededAfter Retry-After seconds with exponential backoff
503Global circuit breaker triggeredAfter 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, and each HTTP request counts once against that quota. A tools/batch call is always rate-limited at the outer MCP request. In atomic mode, supported tools execute inside one service-layer transaction after scope and delegation pre-validation. In non-atomic best-effort mode, each tool is executed through the normal internal API path and may also consume authenticated per-key quota or return 429 from the backing endpoint. Implement backoff for both the outer MCP request cadence and any inner tool-level 429 responses in non-atomic mode.

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: Current server responses document code values in their serialized form. Most use dotted lowercase notation such as category.specific_code (for example validation_error.invalid_fields, conflict.stale_version, and billing.trust_ceiling_exceeded). Some legacy historical codes are shown below for reference, but integrations should match the documented serialized code values returned by current responses.

Recommendation: Use the category field (always present and stable) for broad programmatic handling, then match the exact documented code values you care about. The stable category values are: validation_error, authentication_error, authorization_error, not_found, conflict, rate_limited, security_error, 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

StatusCodeDescription
400validation_error.bad_requestMissing or invalid parameters
400validation_error.invalid_fieldsRequest body failed validation — check details.fields
401authentication_error.invalid_credentialsMissing or invalid API key
401authentication_error.invalid_api_keyAPI key not found
401authentication_error.key_expiredAPI key has expired — generate a new key
401authentication_error.unauthorizedAuthentication required — provide a valid API key or session
401authentication_error.key_rotation_requiredKey exceeds the tenant’s maximum key age — rotate your key
403authorization_error.insufficient_scopeValid key but insufficient permissions or missing scope
403security_error.cors_origin_deniedRequest origin not in key’s allowed origins
403security_error.csrf_token_invalidCSRF token missing or invalid (session-authenticated requests only)
404not_foundResource does not exist or you lack access
405request_error.method_not_allowedHTTP method not supported for this endpoint — check the Allow response header when present
429rate_limitedToo many requests — check X-RateLimit-Reset header
500internal_errorInternal server error — safe to retry with backoff
503transient_errorTransient 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

StatusCodeDescriptionResolution
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?action=topup with amount, success_url, and cancel_url, or use 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 for broad handling, then match the exact documented code values your integration needs. Future releases may add new code values within an existing category, but new categories will always be announced in the changelog.

Authentication Errors (401)

StatusCodeDescriptionRecovery
401authentication_error.invalid_credentialsMissing, malformed, or expired API keyVerify the Authorization: Bearer <key> header. Generate a new key if expired.
401UNAUTHORIZED LEGACYAuthentication failed (legacy format)Same as above. Prefer checking category === 'authentication_error'.

Authorization Errors (403)

StatusCodeDescriptionRecovery
403authorization_error.insufficient_scopeAPI key lacks the required scope for this operationIssue a new key with the required scope, or use a key that already has it. See Scopes.
403FORBIDDEN LEGACYAccess denied (legacy format)Check key scopes.
403INSUFFICIENT_SCOPE LEGACYInsufficient API key scopeAdd the required scope to your API key.
403CORS_ORIGIN_DENIEDRequest origin is not in the key’s allowed origins listAdd the origin to your API key’s allowed origins in the developer settings.
403trust_cap_exceededAgent 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.
403delegation_budget_exceededDeal value exceeds remaining delegation budgetPropose a value within details.remaining_budget, or request a higher delegation limit.

Request Errors (405)

StatusCodeDescriptionRecovery
405request_error.method_not_allowedHTTP method not supported for this endpointCheck the Allow response header for the allowed methods when the endpoint advertises them.
405METHOD_NOT_ALLOWED LEGACYHTTP method not supportedCheck the Allow header.

Validation Errors (400)

StatusCodeDescriptionRecovery
400validation_error.invalid_fieldsOne or more fields failed validation — see details.fieldsFix each field listed in details.fields. Each entry has a code (required, invalid, too_long, etc.) and a human message.
400validation_error.bad_requestRequest is structurally invalid (missing required parameter, wrong type)Read message for specific guidance on what is missing or wrong.
400validation_error.body_too_largeRequest body exceeds the 1 MB limitReduce the request body size.
413validation_error.body_too_largeRequest body exceeds maximum sizeReduce request body to under 1 MB.
428validation_error.precondition_requiredIf-Match header is required for this mutating operationInclude If-Match: W/"<version>" from a prior GET’s ETag header.

Not Found (404)

StatusCodeDescriptionRecovery
404not_foundResource does not exist, has been deleted, or belongs to another tenantVerify the ID is correct. Check that you’re using the right API key for this tenant.
404NOT_FOUND LEGACYResource not found (legacy format)Same as above.

Conflict Errors (409 / 412)

StatusCodeDescriptionRecovery
409conflict.deal_already_closedOperation not permitted on a closed dealCreate a new deal.
409conflict.idempotency_key_reusedIdempotency key was already used with different request bodyUse a new unique idempotency key. If the original request succeeded, fetch the resource to check its state.
412conflict.stale_versionIf-Match version mismatch — someone else updated the resource firstRe-fetch resource (current state in data), merge, and retry with new ETag.

Billing Errors (402)

StatusCodeDescriptionRecovery
402billing.insufficient_creditCredit balance too low to complete the operationTop up via POST /api/v1/credits?action=topup with amount, success_url, and cancel_url. details.shortfall shows the amount needed.
402billing.trust_ceiling_exceededMonthly auto top-up ceiling reached for your trust levelWait until the 1st of next month, or upgrade your trust level.

Rate Limiting (429)

StatusCodeDescriptionRecovery
429rate_limitedToo many requests — global rate limit exceededWait recovery.retry_after_seconds (default 60 s). Implement exponential backoff.
429RATE_LIMIT_EXCEEDED LEGACYToo many requests (legacy format)Check X-RateLimit-Reset header.
429spending_limit_exceededDelegation per-transaction, daily, or monthly limit reachedWait for limit reset. Check details.remaining_daily and details.remaining_monthly.

Server & Transient Errors (500 / 503)

StatusCodeDescriptionRecovery
500internal_errorUnexpected 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.
503transient_errorTemporary outage or circuit breaker openRetry after recovery.retry_after_seconds (default 5 s). Max 3 retries with exponential backoff.
500SERVER_ERROR LEGACYInternal 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 six 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 data.product.product_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 data.customer.customer_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 data.deal.deal_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/payment-intent \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{"deal_id": "deal_xxxxx"}' # Returns a payment client_secret — pass to the payment form 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>

Standard /sdk/v1/... URLs revalidate on each request with ETag via Cache-Control: no-cache, must-revalidate. Fingerprinted version URLs are served as immutable with Cache-Control: public, max-age=31536000, immutable.

Install
npm install @salesbooth/node
Node.js / CommonJS
const { SalesBooth } = require('@salesbooth/node'); const sb = new SalesBooth({ apiKey: 'sb_test_example_key_do_not_use' });

Step 2 — Create a Product

async function main() { 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 } main().catch((error) => { console.error(error); process.exitCode = 1; });

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' }); async function main() { // 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', name: 'Pro Plan', quantity: 1, unit_price: 499.00 }); console.log('Deal created:', deal.deal_id); } main().catch((error) => { console.error(error); process.exitCode = 1; });

SDK Resources: Common SDK resources include sb.deals, sb.customers, sb.products, sb.contracts, sb.webhooks, sb.payments, sb.subscriptions, sb.widgets, sb.tools, and sb.mcp. Each resource exposes the methods documented in the SDK reference; common CRUD resources provide list(), get(), create(), and update(), while workflow resources such as analytics, negotiations, intelligence, and configuration expose resource-specific methods.

Current shipped browser SDK surface: sb.deals, sb.customers, sb.products, sb.contracts, sb.webhooks, sb.audit, sb.discovery, sb.negotiations, sb.templates, sb.intelligence, sb.search, sb.delegations, sb.configuration, sb.productFamilies, sb.optionGroups, sb.productRules, sb.bundleRules, sb.compatibilityRules, sb.savedConfigs, sb.widgets, sb.analytics, sb.payments, sb.gdpr, sb.auditExport, sb.sandbox, sb.workflows, sb.agentTrust, sb.federation, sb.federationPeers, sb.subscriptions, sb.events, sb.dealParticipants, sb.team, sb.availability, sb.staff, sb.bookings, sb.billing, sb.usdc, sb.agentRegistry, sb.tools, sb.mcp, sb.uploads, sb.schema, sb.system, sb.quotes, sb.abTests, sb.fxRate, sb.trust, sb.dealNotifications, sb.productOptionGroups, sb.pricingSimulation, sb.credits, sb.activity, sb.customerAuth, sb.customerPortal, sb.playground, and sb.federationDiscovery.

Step 4 — Transition the Deal

const { SalesBooth } = require('@salesbooth/node'); const sb = new SalesBooth({ apiKey: 'sb_test_example_key_do_not_use' }); async function main() { // Use the deal_id returned in Step 3 await sb.deals.transition('deal_xxxxx', 'in_progress'); console.log('Deal ready:', 'deal_xxxxx'); } main().catch((error) => { console.error(error); process.exitCode = 1; });

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", "api_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' }); async function main() { // Get AI score for a deal const score = await sb.intelligence.scoreDeal('deal_abc123'); console.log('Score:', score.score); console.log('Win probability:', score.win_probability); console.log('Recommendation:', score.recommendation); console.log('Explanation:', score.explanation); Object.entries(score.factors).forEach(([name, factor]) => { console.log(`${name}: ${factor.points}/${factor.max_points} - ${factor.detail}`); }); // 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.risk_level !== 'low') { const highRisk = risk.risk_factors.filter(f => f.severity === 'high'); highRisk.forEach(f => console.warn(`Risk: ${f.type} — ${f.action}`)); } // Get pipeline forecast for next 90 days const forecast = await sb.intelligence.forecastPipeline({ period: '90' }); console.log(`90-day weighted pipeline: $${forecast.total_weighted_pipeline.toLocaleString()}`); console.log(`Forecast windows: ${Object.keys(forecast.windows).join(', ')}`); } main().catch((error) => { console.error(error); process.exitCode = 1; });

Step 7 — Negotiate Deal Terms (optional)

const { SalesBooth } = require('@salesbooth/node'); const sb = new SalesBooth({ apiKey: 'sb_test_example_key_do_not_use' }); async function main() { // 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 best = suggestions.suggestions[0]; console.log('AI suggests:', best.recommended_terms, `(confidence: ${best.confidence}%)`); // Counter with AI-suggested terms await sb.negotiations.counter('deal_abc123', { proposed_terms: best.recommended_terms, message: best.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.total_rounds} rounds`); } main().catch((error) => { console.error(error); process.exitCode = 1; });

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' }); async function main() { // 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'); const sigBuf = Buffer.from(sig); const expectedBuf = Buffer.from(expected); if (sigBuf.length !== expectedBuf.length || !crypto.timingSafeEqual(sigBuf, expectedBuf)) 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; } } main().catch((error) => { console.error(error); process.exitCode = 1; });

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' }); async function main() { // 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 let deal = await sb.deals.create({ title: 'Pro Plan — Jane Smith', customer_id: customer.customer_id, currency: 'USD', tax_rate: 0.10 }); deal = await sb.deals.addItem(deal.deal_id, { product_id: product.product_id, name: product.name || 'Pro Plan', quantity: 5, unit_price: product.price }); // Apply discount and transition deal = await sb.deals.applyDiscount(deal.deal_id, { type: 'percentage', value: 10 }); deal = await sb.deals.transition(deal.deal_id, 'in_progress'); console.log(`Deal ${deal.deal_id} ready — total: $${deal.total}`); } main().catch((error) => { console.error(error); process.exitCode = 1; });

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

Install the official Python SDK for typed methods, automatic retries, and idempotency key management.

Install
pip install salesbooth
Python — Create a customer and deal
import salesbooth client = salesbooth.SalesBooth(api_key="sb_test_example_key_do_not_use") # Create a customer customer = client.customers.create( name="Jane Smith", email="jane@example.com", company="Acme Corp" ) print("Customer:", customer["customer_id"]) # Create a deal deal = client.deals.create( title="Pro Plan — Jane Smith", customer_id=customer["customer_id"], currency="USD", tax_rate=0.10 ) print("Deal:", deal["deal_id"]) # Add a line item client.deals.add_item( deal["deal_id"], product_id="prod_xxxxx", name="Pro Plan", quantity=1, unit_price=499.00 ) print("Line item added") # Transition to in_progress deal = client.deals.transition(deal["deal_id"], "in_progress") print("Deal transitioned:", deal["status"])
Python — Verify a webhook signature
import salesbooth from salesbooth.errors import WebhookVerificationError from flask import Flask, request, abort app = Flask(__name__) WEBHOOK_SECRET = "your_webhook_signing_secret" @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(as_text=True) # raw string — do NOT parse before verifying try: salesbooth.verify_signature(body, sig, WEBHOOK_SECRET, timestamp) except WebhookVerificationError as e: abort(400, str(e)) event = request.get_json() print(f"Event: {event['event']} id={event['id']}") return "", 200
Python — Raw HTTP with requests library
import requests import hmac import hashlib API_KEY = "sb_test_example_key_do_not_use" BASE_URL = "https://api.salesbooth.com/v1" HEADERS = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json", } # Create a customer resp = requests.post( f"{BASE_URL}/customers", headers=HEADERS, json={"name": "Jane Smith", "email": "jane@example.com", "company": "Acme Corp"}, ) resp.raise_for_status() customer = resp.json()["data"]["customer"] print("Customer:", customer["customer_id"]) # Create a deal resp = requests.post( f"{BASE_URL}/deals", headers=HEADERS, json={"title": "Example Deal", "customer_id": customer["customer_id"], "currency": "USD", "tax_rate": 0.10}, ) resp.raise_for_status() deal = resp.json()["data"]["deal"] print("Deal:", deal["deal_id"]) # Verify a webhook signature manually with hmac/hashlib def verify_signature(payload: str, timestamp: str, signature: str, secret: str) -> bool: signed_content = f"{timestamp}.{payload}" expected = "v1=" + hmac.new(secret.encode(), signed_content.encode(), hashlib.sha256).hexdigest() return hmac.compare_digest(expected, signature)

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

TopicJump to
Receive real-time events for deal changes, payments, and renewalsWebhooks
Let buyers propose & counter deal termsNegotiations
Build AI agents that negotiate and close deals autonomouslyAgent Integration
Grant sub-agents constrained spending authorityDelegations
Embed a configurable deal widget on your siteWidgets
Score deals and get AI pricing suggestionsIntelligence API
Configure product bundles, options, and rulesCPQ / Configuration
Full REST reference — every endpoint, parameter, and responseCore 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

POST endpoints that create or mutate financial records and document Idempotency-Key support accept 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-processing the operation.

Use idempotency keys for: POST /deals, POST /payment-intent, POST /payments, POST /subscriptions, POST /contracts. Keys must be unique per request, 1–255 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", "title": "Order 2026-03-17", "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", "title": "Order 2026-03-17", "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)

Write endpoints and actions that route request bodies through RequestValidator accept only the explicitly documented fields shown in their parameter tables. By default, undocumented or system-controlled fields sent in the request body are stripped from the validated payload and never persisted. Endpoints or actions that use strict validation instead reject unknown fields with 400 validation_error.invalid_fields; the offending entries appear in details.fields with code unknown_field. Other endpoints may apply endpoint-specific validation instead of this centralized contract. This prevents mass-assignment attacks where validator-backed routes might otherwise allow a client to 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 — on deal creation, only safe initial values are accepted (draft, in_progress); after creation, status changes require the action=transition endpoint. payment_status, contract_status — always controlled by state machine transitions
  • 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

Strict validation is used on some write actions where the request schema must match exactly. For example, deal actions such as escrow, record-outcome, set-terms (wrapper format), and partial_accept reject unknown request fields instead of ignoring them.

After creation, deal status changes must use the action=transition action endpoint, which enforces the state machine rules. Direct status writes on PATCH are rejected.

Input Validation

Inputs are always subject to server-side checks, but the exact contract is endpoint-specific. Routes and actions that use RequestValidator validate inputs before database writes and return 400 validation_error.invalid_fields with a details.fields map indicating which fields failed and why. Other endpoints may rely on resource-specific guards or different error responses, so check the endpoint documentation before assuming centralized validation coverage. Client-side validation should be considered a UX improvement only — never rely on it for security.

Rule enforcedExample
Numeric rangesdeposit_pct must be 0–1; negative values or values >1 are rejected with validation_error.out_of_range
Required fieldsMissing required fields return per-field errors in details.fields
String lengthsNames max 255 chars, descriptions max 10,000 chars
Currency codesMust match ISO 4217 (e.g. USD, EUR, AUD)
Tax ratesStored as decimal(5,4); values ≥1 are treated as a percentage and normalised (e.g. 100.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.

LayerMechanism
In transitTLS 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 keysStored as bcrypt hashes; plaintext is shown only at creation time
Webhook secretsStored 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 payment provider — raw card numbers never pass through Salesbooth servers. Salesbooth stores only payment provider PaymentIntent IDs and tokenised payment method references.

Your integration scope is reduced: Because card data flows directly from the buyer’s browser to payment provider’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 payment provider’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:

OperationRequired scopeNotes
Read deals / customersdeals:read / customers:readRead-only; safe for reporting integrations
Create/modify dealsdeals:writeServer-side only; never expose in browser JS
Modify contracts or templatescontracts:writeRestrict to admin-level server keys
Configure paymentsdeals:write + payment provider connectionRequires separate payment provider OAuth; finance team only
Widget / browser embeddingPublishable key (sb_pub_*)Auto-scoped to products:read, customers:write, deals:write, agent:negotiate only
Audit export / complianceaudit:exportSeparate 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.

GET /api/v1/deals
List deals with optional filters, or retrieve a single deal by ID. Returns paginated results.
ParameterDescription
idDeal ID to retrieve a specific deal (e.g. deal_xxxxxxxxxx). When provided, returns a single deal object instead of a list.
actionLegacy compatibility mode for older integrations. Prefer the canonical sub-resource routes below such as /deals/{id}/terms, /deals/{id}/audit, /deals/compare-terms, and /deals/export. The query-action forms remain supported.
deal_id_1First deal ID for the legacy action=compare-terms alias
deal_id_2Second deal ID for the legacy action=compare-terms alias
statusFilter: draft, in_progress, pending_signature, awaiting_signatures, pending_payment, partially_accepted, closed, cancelled, expired
customer_idFilter by customer ID
created_afterISO 8601 date filter
created_beforeISO 8601 date filter
min_valueFilter deals with total value >= this amount (used with action=export)
max_valueFilter deals with total value <= this amount (used with action=export)
searchSearch by deal title or deal ID
limitMax results, 1–100 (default: 50)
offsetPagination offset (default: 0). Ignored when after/before cursors are provided.
afterCursor for forward pagination. Pass the next_cursor from a previous response.
beforeCursor for backward pagination. Pass the prev_cursor from a previous response.
sortSort field for cursor pagination: created_at (default) or updated_at
fieldsComma-separated list of fields to include in the response (e.g. id,status,total)
includeComma-separated nested resources to include (e.g. line_items,pricing,customer)
excludeComma-separated nested resources to exclude from the response
formatResponse format shortcut: minimal returns only id, status, and updated_at
GET /api/v1/deals?id={deal_id}
Retrieve a single deal with its line items and signatures.
POST /api/v1/deals
Create a new deal.
FieldTypeDescription
title requiredstringDeal title (max 255 chars)
customer_idstringCustomer identifier (omit for widget negotiations or draft deals)
descriptionstringDeal description
currencystringISO 4217 currency code (default: USD)
tax_ratenumberTax rate as decimal (e.g. 0.10 for 10%). Values ≥1 are accepted for compatibility and auto-normalized (e.g. 100.10); prefer decimal form.
deal_typestringone_time (default) or recurring
billing_cyclestringmonthly, quarterly, or annual (required when deal_type is recurring)
presentation_currencystringISO 4217 currency for display (auto-converted from currency)
settlement_currencystringISO 4217 currency for settlement
statusstringInitial status (default: draft)
notesstringInternal notes (not visible to customers)
metadataobjectArbitrary key-value metadata (max depth 3)
deposit_requirednumberRequired deposit amount from the buyer. When set, payment-intent fallback charges this amount instead of the full total.
template_idstringDeal template ID to create from (pre-populates fields from template)

Query parameter: ?validate_only=true — validates the request body without creating the deal. Returns {"valid": true, "message": "Validation passed"} on success.

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" } } }
PATCH /api/v1/deals?id={deal_id}
Update deal fields. Send only the fields you want to change. Requires an If-Match header with the current ETag version for optimistic locking.
FieldTypeDescription
customer_idstringCustomer ID to reassign this deal to
titlestringDeal title
descriptionstringDeal description
notesstringInternal notes
currencystringISO 4217 currency code (e.g. USD)
tax_ratenumberTax rate as decimal (e.g. 0.10 for 10%). Values ≥1 are accepted for compatibility and auto-normalized (e.g. 100.10); prefer decimal form.
deposit_requirednumberRequired deposit amount in the deal currency. Must be ≥ 0.
deal_typestringone_time or recurring
billing_cyclestringmonthly, quarterly, or annual
metadataobjectArbitrary key-value metadata (max depth 3)

Note: Deal status cannot be changed via PATCH. Use POST /deals?id={deal_id}&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: W/\"3\"" \ -d '{ "currency": "AUD", "tax_rate": 0.10, "notes": "Updated pricing agreed in call" }'
DELETE /api/v1/deals?id={deal_id}
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. When cancelling, optional reason and notes metadata may be sent either as query parameters or in a JSON request body.
FieldTypeDescription
reasonstringOptional cancellation reason. Allowed values: price, competitor, timing, budget, fit, no_response, champion_left, terms, or other.
notesstringOptional free-text notes recorded with the cancellation.
Example — Cancel deal with metadata
curl -X DELETE "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: W/\"1\"" \ -d '{ "reason": "price", "notes": "Customer chose a lower-priced annual offer from an incumbent vendor" }'
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: W/\"1\""
Response (200) — cancel
{ "error": false, "success": true, "data": { "message": "Deal cancelled successfully", "deal_id": "deal_xxxxx", "deal": { "deal_id": "deal_xxxxx", "version": 2, "status": "cancelled", "currency": "USD", "line_items": [], "pricing": { "currency": "USD", "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:31:00Z" } } }
Response (200) — remove_item
{ "error": false, "success": true, "data": { "message": "Item removed", "item_id": "item_yyyyy", "deal": { "deal_id": "deal_xxxxx", "version": 2, "status": "draft", "currency": "USD", "line_items": [], "pricing": { "currency": "USD", "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:31:00Z" } } }

Deal Actions

POST /api/v1/deals?id={deal_id}&action=add_item
Add a line item to a deal.
FieldTypeDescription
product_id requiredstringProduct to add
name requiredstringLine item display name
unit_price requirednumberUnit price
quantityintegerQuantity (default 1)
descriptionstringLine item description
configurationobjectSelected configuration options
price_typestringPricing model: once_off, recurring, or metered
billing_cyclestringBilling frequency: monthly, quarterly, or annual. Required when price_type is recurring or metered
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, "price_type": "recurring", "billing_cycle": "monthly" }'
GET /api/v1/deals/{id}/valid-transitions
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" } } ] } }

Tip: Each transition's action.endpoint field provides the ready-to-use URL for executing that state change.

POST /api/v1/deals?id={deal_id}&action=transition&status={status}
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.
POST /api/v1/deals?id={deal_id}&action=sign
Cryptographically sign a deal. Creates a verifiable signature with hash chain.
FieldTypeDescription
signer_typestringuser, customer, agent, or api_key
signer_idstringID of the signer (optional; defaults to the authenticated identity)
signer_customer_idstringCustomer 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_signbooleanRequired 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}'
POST /api/v1/deals?id={deal_id}&action=unsign
Remove the signature from a deal, reverting it to an unsigned state. Only valid while the deal has not been closed.
FieldTypeDescription
reasonstringOptional 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"}'
POST /api/v1/deals?id={deal_id}&action=update_item&item_id={item_id}
Update the quantity or unit price of an existing line item on a deal. The item_id query parameter is required.
FieldTypeDescription
quantity optionalintegerNew quantity (minimum: 1)
unit_price optionalnumberOverride unit price for the line item (minimum: 0)
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}'
POST /api/v1/deals?id={deal_id}&action=apply_discount
Apply a discount to a deal. Discounts can be a fixed amount or a percentage of the deal total.
FieldTypeDescription
type requiredstringpercentage or fixed
value requirednumberDiscount value — percentage points (e.g. 10 for 10% off) or fixed currency amount
codestringOptional promo code associated with this discount
descriptionstringHuman-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" }'
POST /api/v1/deals?id={deal_id}&action=set-terms
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.
FieldTypeDescription
terms requiredobjectDeal terms object. Provide schema-shaped fields such as payment_terms, delivery, and warranty. The server validates the object and stamps the canonical terms_schema_version. 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": { "payment_terms": { "type": "net_30", "due_date": "2026-04-30T00:00:00Z" }, "delivery": { "method": "digital", "estimated_days": 5 }, "warranty": { "duration_days": 365 } } }'
POST /api/v1/deals?action=create-configured
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 either the deals:write or agent:execute API key scope.
FieldTypeDescription
customer_idstringExisting customer ID. Provide either customer_id or customer (inline create)
customerobjectInline customer: name, email, phone, company. Creates the customer if they don't exist (matched by email)
itemsarrayLine items array. Each item: product_id, quantity, unit_price, name, optional configuration with option_ids
saved_config_idstringSaved product configuration ID. Use instead of items to populate line items from a saved configuration
discountsarrayOptional discounts array. Each entry: type (percentage or fixed), value, code (promo code for tracking), description (human-readable label)
template_idstringOptional deal template to apply default settings from
currencystringISO 4217 currency code (e.g. USD)
notesstringInternal notes
metadataobjectArbitrary key-value metadata
dry_runbooleanIf 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 '{ "title": "Acme annual plan", "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" }'
POST /api/v1/deals?id={deal_id}&action=partial_accept
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.
FieldTypeDescription
accepted_items requiredarrayArray of line item IDs to accept (at least one required)
rejected_itemsarrayArray of line item IDs being explicitly rejected (informational)
create_declined_dealbooleanIf 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 }'
POST /api/v1/deals?id={deal_id}&action=escrow
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.
FieldTypeDescription
conditions requiredarrayArray of condition objects, each with type (e.g. delivery, approval) and optional config
amountnumberAmount to hold in escrow. Defaults to the deal total
currencystringISO 4217 currency code. Defaults to the deal currency
expires_inintegerSeconds 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 }'
POST /api/v1/deals?id={deal_id}&action=release_escrow
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"
POST /api/v1/deals?id={deal_id}&action=refund_escrow
Refund escrowed funds back to the buyer and cancel the escrow hold. Triggers the escrow.refunded webhook event.
FieldTypeDescription
reasonstringReason 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"}'
POST /api/v1/deals?id={deal_id}&action=fulfill_condition
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.
FieldTypeDescription
condition_id requiredstringID of the escrow condition to mark as fulfilled
met_bystringOptional 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" }'
POST /api/v1/deals?id={deal_id}&action=revoke_credential
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.
FieldTypeDescription
reasonstringReason 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"}'
POST /api/v1/deals?id={deal_id}&action=record-outcome
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.
FieldTypeDescription
reason requiredstringOutcome reason. Accepted values: price, competitor, timing, budget, fit, no_response, champion_left, terms, or other
notesstringFree-text notes about the outcome (stored in audit log)
competitor_namestringName of the competitor chosen instead (for loss analysis)
Example — Budget constraint
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": "budget", "notes": "Prospect paused rollout after budget review on 2026-03-28"}'
Example — Competitor selected
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": "competitor", "notes": "Went with competitor on price", "competitor_name": "CompetitorCo" }'
POST /api/v1/deals?id={deal_id}&action=save-as-template
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.
FieldTypeDescription
name requiredstringTemplate name (1–255 characters)
descriptionstringOptional 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" }'
GET /api/v1/deals/{id}/audit
Retrieve the immutable audit trail for a deal. Legacy alias: GET /api/v1/deals?id={deal_id}&action=audit.
GET /api/v1/deals/{id}/verify-audit
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. Legacy alias: GET /api/v1/deals?id={deal_id}&action=verify_audit.
Example
curl "https://api.salesbooth.com/v1/deals/deal_xxxxx/verify-audit" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{ "error": false, "success": true, "data": { "status": "verified", "total_entries": 14, "verified_at": "2026-05-14T04:00:00Z" } }
GET /api/v1/deals/{id}/escrow
Retrieve the current escrow status for a deal, including held amount, conditions, release/refund state, and authorization window details. Requires deals:read scope when using bearer auth or API keys; session auth is also supported. Legacy alias: GET /api/v1/deals?id={deal_id}&action=escrow.
Example
curl "https://api.salesbooth.com/v1/deals/deal_xxxxx/escrow" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{ "error": false, "success": true, "data": { "escrow_id": "esc_a1b2c3d4e5f6g7h8", "deal_id": "deal_xxxxx", "amount": 4500, "currency": "AUD", "status": "held", "conditions": [ {"type": "delivery", "config": {"tracking_required": true}}, {"type": "approval"} ], "conditions_summary": { "total": 2, "met": 1, "remaining": 1, "all_met": false }, "authorization": { "last_authorized_at": "2026-05-14T04:00:00Z", "auth_expires_at": "2026-05-21T04:00:00Z", "auth_days_remaining": 7, "auth_status": "ok" }, "released_at": null, "refunded_at": null, "expires_at": "2026-05-21T04:00:00Z", "created_at": "2026-05-14T04:00:00Z", "updated_at": "2026-05-14T04:00:00Z" } }
GET /api/v1/deals/{id}/credential
Retrieve the verifiable credential issued for a deal, including issuance metadata, credential hash, revocation state, and the signed W3C credential payload. Requires deals:read scope when using bearer auth or API keys; session auth is also supported. Legacy alias: GET /api/v1/deals?id={deal_id}&action=credential.
Example
curl "https://api.salesbooth.com/v1/deals/deal_xxxxx/credential" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{ "error": false, "success": true, "data": { "credential_id": "cred_abc123", "deal_id": "deal_xxxxx", "status": "active", "key_id": "key_2026_05", "credential_hash": "4e5f6a7b8c9d...", "issued_at": "2026-05-14T04:00:00Z", "revoked_at": null, "revocation_reason": null, "credential": { "@context": [ "https://www.w3.org/2018/credentials/v1" ], "type": ["VerifiableCredential", "DealCompletionCredential"], "issuer": "https://salesbooth.com", "issuanceDate": "2026-05-14T04:00:00Z", "credentialSubject": { "deal_id": "deal_xxxxx", "status": "closed" }, "proof": { "type": "HmacSha256Signature2024", "created": "2026-05-14T04:00:00Z", "verificationMethod": "https://salesbooth.com/keys/key_2026_05", "proofPurpose": "assertionMethod", "signatureValue": "9f3c8d7e6b5a4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9d" } } } }
GET /api/v1/deals/{id}/terms
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. Legacy alias: GET /api/v1/deals?id={deal_id}&action=terms.
Example
curl "https://api.salesbooth.com/v1/deals/deal_xxxxx/terms" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{ "error": false, "success": true, "data": { "deal_id": "deal_xxxxx", "terms_schema_version": "1.0", "terms": { "terms_schema_version": "1.0", "payment_terms": { "type": "net_30", "due_date": "2026-04-30T00:00:00Z" }, "delivery": { "method": "digital", "estimated_days": 5 }, "warranty": { "duration_days": 365 } } } }
GET /api/v1/deals/compare-terms?deal_id_1={id_1}&deal_id_2={id_2}
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. Legacy alias: GET /api/v1/deals?action=compare-terms&deal_id_1={id_1}&deal_id_2={id_2}.
ParameterTypeDescription
deal_id_1 requiredstringFirst deal ID
deal_id_2 requiredstringSecond deal ID to compare against
Example
curl "https://api.salesbooth.com/v1/deals/compare-terms?deal_id_1=deal_aaaaa&deal_id_2=deal_bbbbb" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
GET /api/v1/deals/{id}/signing-certificate
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. Legacy alias: GET /api/v1/deals?id={deal_id}&action=signing_certificate.
Example
curl "https://api.salesbooth.com/v1/deals/deal_xxxxx/signing-certificate" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{ "error": false, "success": true, "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": "pending_payment", "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." } }
GET /api/v1/deals/export?format={format}
Bulk export deals as text/csv, application/json, or application/x-ndjson. 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. Legacy alias: GET /api/v1/deals?action=export&format={format}.
ParameterTypeDescription
formatstringOutput format: csv (default), json, or jsonl
statusstringFilter by deal status (e.g. closed, draft)
created_afterstringISO 8601 date — only include deals created after this date
created_beforestringISO 8601 date — only include deals created before this date
customer_idstringFilter to deals for a specific customer
Example — CSV export
curl "https://api.salesbooth.com/v1/deals/export?format=csv&status=closed" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -o deals.csv
Example — JSONL export
curl "https://api.salesbooth.com/v1/deals/export?format=jsonl&created_after=2026-01-01" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -o deals.jsonl
GET /api/v1/deals/{id}/settlements
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": "payment_provider", "payment_provider_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", "payment_provider_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 } } ] } }
GET /api/v1/deals/verify?id={deal_id}
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.
ParameterTypeDescription
idstringDeal ID to verify (provide either id or contract_id)
contract_idstringContract ID to verify
Example
curl "https://api.salesbooth.com/v1/deals/verify?id=deal_abc123"
Response
{ "error": false, "success": true, "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.

GET /api/v1/customers
List customers with optional filters.
ParameterDescription
idCustomer ID to retrieve a specific customer (e.g. cust_xxxxxxxxxx). When provided, returns a single customer object instead of a list.
statusFilter: active, inactive, archived
searchSearch name, email, phone, or company
limitMax results, 1–100 (default: 50)
offsetPagination offset (default: 0). Ignored when after/before cursors are provided.
afterCursor for forward pagination. Pass the next_cursor from a previous response.
beforeCursor for backward pagination. Pass the prev_cursor from a previous response.
sortSort field for cursor pagination: created_at (default) or updated_at
fieldsComma-separated list of fields to include in the response (e.g. id,status,name)
includeComma-separated nested resources to include (e.g. deals,contracts,activity_log)
excludeComma-separated nested resources to exclude from the response
formatResponse format shortcut: minimal returns only id, status, and updated_at
customer_idDeprecated. Alias for id. Use id instead.
GET /api/v1/customers?id={customer_id}
Retrieve a single customer with their deals and activity log.
POST /api/v1/customers
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" }'
FieldDescription
name requiredCustomer full name
email requiredEmail address
phonePhone number (E.164 format)
companyCompany or organisation name
cityCity
stateState or region
zipPostal code
countryCountry code (e.g. AU)
addressStreet address
notesInternal notes
statusCustomer status: active (default), inactive, archived

Query parameter: ?validate_only=true — validates the request body without creating the customer. Returns {"valid": true, "message": "Validation passed"} on success.

PATCH /api/v1/customers?id={customer_id}
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.
FieldTypeDescription
namestringFull name
emailstringEmail address (must be unique per tenant)
phonestringPhone number (normalised to E.164)
addressstringStreet address
companystringCompany name
citystringCity
statestringState or province
zipstringPostal code
countrystringCountry
notesstringInternal notes
statusstringactive, 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: W/\"5\"" \ -d '{ "phone": "+14155552671", "company": "Acme Corp (updated)", "status": "active" }'
DELETE /api/v1/customers?id={customer_id}
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: W/\"1\""

Products

Manage your product catalogue. Products can be physical goods or services and are referenced by deal line items.

GET /api/v1/products
List products with optional filters.
ParameterDescription
idProduct ID to retrieve a specific product (e.g. prod_xxxxxxxxxx). When provided, returns a single product object instead of a list.
actionSub-action to perform: options (requires id) — returns the product’s configuration options schema
statusFilter: active, inactive, archived
typeFilter: product, service, subscription, bundle
categoryFilter by category name
familyFilter by product family ID
requires_bookingFilter to bookable service products: 1 to include only bookable products, 0 to exclude them
searchSearch name, SKU, or description
limitMax results, 1–100 (default: 50)
offsetPagination offset (default: 0). Ignored when after/before cursors are provided.
afterCursor for forward pagination. Pass the next_cursor from a previous response.
beforeCursor for backward pagination. Pass the prev_cursor from a previous response.
sortSort field for cursor pagination: created_at (default) or updated_at
fieldsComma-separated list of fields to include in the response (e.g. id,status,name,price)
includeComma-separated nested resources to include (e.g. deals,activity_log)
excludeComma-separated nested resources to exclude from the response
formatResponse format shortcut: minimal returns only id, status, and updated_at
product_idDeprecated. Alias for id. Use id instead.
POST /api/v1/products
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" }'
FieldTypeDescription
name requiredstringProduct name
price requirednumberSelling price
descriptionstringProduct description
skustringStock keeping unit
typestringproduct, service, subscription, or bundle
price_typestringonce_off, recurring, percentage, or metered
billing_cyclestringmonthly, quarterly, or annual — required when price_type is recurring or metered
pricing_modelstringfixed, tiered, volume, or usage
costnumberCost price (for margin calculation)
unitstringUnit label (e.g. “per seat”, “per month”)
tax_ratenumberTax rate as decimal (e.g. 0.10 for 10%)
categorystringProduct category
statusstringactive, inactive, or archived (default: active)
stock_quantityintegerAvailable stock quantity
track_inventorybooleanEnable inventory tracking for this product
low_stock_thresholdintegerStock level at which low-stock alerts are triggered
metadataobjectArbitrary key-value metadata
configuration_schemaobjectJSON schema defining configurable options for this product
family_idstringProduct family ID to associate this product with
requires_bookingbooleanWhether this product requires a booking (default: false)
session_durationintegerSession length in minutes (5–480)
buffer_timeintegerBuffer time between sessions in minutes (0–120)
max_advance_daysintegerMaximum days in advance a booking can be made (default: 90)
min_advance_hoursintegerMinimum hours lead time required for a booking (default: 24)
allow_staff_selectionbooleanWhether customers can choose their preferred staff member (default: true)
learn_more_urlstringURL linking to more information about the product
featuresarrayList of product feature strings

Query parameter: ?validate_only=true — validates the request body without creating the product. Returns {"valid": true, "message": "Validation passed"} on success.

PATCH /api/v1/products?id={product_id}
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.
FieldTypeDescription
namestringProduct name
descriptionstringProduct description
pricenumberUnit price
costnumberCost price (for margin calculation)
skustringStock keeping unit
typestringproduct, service, subscription, or bundle
unitstringUnit label (e.g. “per seat”)
tax_ratenumberTax rate as decimal (e.g. 0.10 for 10%)
categorystringProduct category
statusstringactive, inactive, or archived
stock_quantityintegerAvailable stock quantity
track_inventorybooleanEnable inventory tracking
low_stock_thresholdintegerStock level at which low-stock alerts are triggered
price_typestringonce_off, recurring, percentage, or metered
billing_cyclestringmonthly, quarterly, or annual — required when price_type is recurring or metered
pricing_modelstringfixed, tiered, volume, or usage
metadataobjectArbitrary key-value metadata
configuration_schemaobjectJSON schema defining configurable options for this product
family_idstringProduct family ID to associate this product with
requires_bookingbooleanWhether this product requires a booking
session_durationintegerSession length in minutes (5–480)
buffer_timeintegerBuffer time between sessions in minutes (0–120)
max_advance_daysintegerMaximum days in advance a booking can be made
min_advance_hoursintegerMinimum hours lead time required for a booking
allow_staff_selectionbooleanWhether customers can choose their preferred staff member
learn_more_urlstringURL linking to more information about the product
featuresarrayList 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: W/\"2\"" \ -d '{ "price": 1199.00, "status": "active", "stock_quantity": 50 }'
DELETE /api/v1/products?id={product_id}
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: W/\"1\""

Contracts

Create and manage contracts with lifecycle transitions, cryptographic signing, and immutable audit trails.

GET /api/v1/contracts
List contracts with optional filters.
ParameterDescription
idContract ID to retrieve a specific contract. When provided, returns a single contract object instead of a list.
contract_idDeprecated. Alias for id. Use id instead.
actionAction to perform (requires id): audit, verify_audit, signing_certificate
statusFilter: draft, pending, signed, active, expired, terminated
customer_idFilter by customer
renewal_typeFilter by renewal type: manual, auto, none
expiring_soonFilter contracts expiring within N days (e.g. 30 for contracts expiring in the next 30 days)
limitMax results, 1–100 (default: 50)
offsetPagination offset (default: 0). Ignored when after/before cursors are provided.
afterCursor for forward pagination. Pass the next_cursor from a previous response.
beforeCursor for backward pagination. Pass the prev_cursor from a previous response.
sortSort field for cursor pagination: created_at (default) or updated_at
fieldsComma-separated list of fields to include in the response (e.g. contract_id,status,title,value)
includeComma-separated nested resources to include (e.g. activity_log)
excludeComma-separated nested resources to exclude from the response
POST /api/v1/contracts
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" }'
FieldDescription
deal_idCreate 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_numberCustom contract reference number (e.g. CTR-2026-001).
descriptionContract description.
currencyISO 4217 currency code (default: USD).
payment_termsPayment terms text (e.g. net30).
renewal_typeRenewal configuration: auto, manual, or none (default: manual).
renewal_termsStructured renewal terms object (JSON). Stores renewal period, notice window, and other renewal-specific configuration.
notesInternal notes (not visible to the customer).

* Required unless deal_id is provided.

Query parameter: ?validate_only=true — validates the request body without creating the contract. Returns {"valid": true, "message": "Validation passed"} on success.

PATCH /api/v1/contracts?id={contract_id}
Update fields on an existing contract. Requires an If-Match header with the current ETag for optimistic locking.
FieldDescription
titleContract title
descriptionContract description.
valueContract value (numeric, ≥ 0)
currencyISO 4217 currency code
start_dateContract start date (YYYY-MM-DD)
end_dateContract end date (YYYY-MM-DD, must be after start_date)
renewal_typeRenewal configuration: auto, manual, or none
renewal_termsStructured renewal terms object (JSON). Stores renewal period, notice window, and other renewal-specific configuration.
payment_termsPayment terms text (e.g. net30)
notesInternal notes (not visible to the customer).
customer_idReassign the contract to a different customer.
contract_numberCustom 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: W/\"1\"" \ -d '{ "title": "Annual SaaS Agreement (Revised)", "payment_terms": "net30", "end_date": "2027-01-31" }'
DELETE /api/v1/contracts?id={contract_id}
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: W/\"2\""

Contract Actions

POST /api/v1/contracts?id={contract_id}&action=sign
Sign a draft contract. Creates a cryptographic signature.
POST /api/v1/contracts?id={contract_id}&action=activate
Activate a signed contract.
POST /api/v1/contracts?id={contract_id}&action=terminate
Terminate an active contract.
POST /api/v1/contracts?id={contract_id}&action=renew
Manually trigger contract renewal. Creates a new contract period based on the original terms.
POST /api/v1/contracts?id={contract_id}&action=opt_out_renewal
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 payment intents. Create payment intents, confirm payments, issue refunds, and record manual payments.

GET /api/v1/payments?deal_id={deal_id}
Get payment status for a deal, including payment intent details and payment history.
ParameterTypeDescription
deal_id requiredstringThe deal identifier
Example
curl https://api.salesbooth.com/v1/payments?deal_id=deal_abc123 \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
GET /api/v1/payments?action=settings
Retrieve payment provider settings and payment provider connection status.
Example
curl https://api.salesbooth.com/v1/payments?action=settings \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
POST /api/v1/payments?action=create-intent
Deprecated — use POST /api/v1/payment-intent instead. Create a payment intent for a deal. Returns a client secret for frontend payment confirmation.
FieldTypeDescription
deal_id requiredstringThe deal to collect payment for
amountnumberAmount in major currency units (defaults to deal total)
currencystringISO 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 (201)
{ "error": false, "success": true, "data": { "payment_intent_id": "pi_xxxxx", "client_secret": "pi_xxxxx_secret_xxxxx", "amount": 1099.00, "currency": "usd", "status": "requires_payment_method", "existing": false } }
POST /api/v1/payments?action=confirm
Confirm a payment intent after the customer has provided a payment method.
FieldTypeDescription
deal_id requiredstringThe deal to confirm payment for
payment_intent_id requiredstringThe payment intent 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" }'
POST /api/v1/payments?action=refund
Issue a full or partial refund on a completed payment.
FieldTypeDescription
deal_id requiredstringThe deal to refund
amountnumberPartial refund amount (omit for full refund)
reasonstringRefund 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" }'
POST /api/v1/payments?action=record-manual
Record a manual (offline) payment for a deal — bank transfer, cheque, or cash.
FieldTypeDescription
deal_id requiredstringThe deal identifier
amount requirednumberPayment amount (minimum 0.01)
method requiredstringPayment method: cash, wire, cheque, bank_transfer, or other
referencestringReference number or identifier for the payment
notesstringAdditional 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" }'
POST /api/v1/payments?action=capture
Capture a previously-authorized PaymentIntent that is in requires_capture state.
FieldTypeDescription
deal_id requiredstringThe deal the payment belongs to
payment_intent_id requiredstringThe payment intent ID to capture
amount_to_capturenumberAmount 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, "success": true, "data": { "payment_intent_id": "pi_xxxxx", "captured_amount": 1099.00, "currency": "usd", "payment_status": "succeeded", "deal_status": "closed" } }
POST /api/v1/payments?action=charge-saved-method
Charge a customer's saved payment method off-session. Intended for agent-driven payment collection.
FieldTypeDescription
deal_id requiredstringThe deal to charge payment for
customer_id requiredstringThe customer whose saved payment method to charge
payment_method_idstringSpecific saved 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, "success": true, "data": { "payment_intent_id": "pi_xxxxx", "amount": 1099.00, "currency": "usd", "payment_status": "succeeded", "deal_status": "closed", "balance_due": 0.00 } }
POST /api/v1/payments?action=poll-intent
Poll the current status of a payment intent. Useful for agents that need to check payment state without relying on webhooks.
FieldTypeDescription
payment_intent_id requiredstringThe payment intent 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, "success": true, "data": { "payment_intent_id": "pi_xxxxx", "status": "succeeded", "amount": 1099.00, "amount_received": 1099.00, "currency": "usd", "last_payment_error": null } }
POST /api/v1/payments?action=generate-link
Generate a hosted checkout Session URL so a customer can complete payment via a hosted page. Intended for agent-driven payment link delivery.
FieldTypeDescription
deal_id requiredstringThe deal to generate a payment link for
success_urlstringURL to redirect the customer to after successful payment
cancel_urlstringURL 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, "success": true, "data": { "payment_link": "https://checkout.salesbooth-payments.example/pay/cs_xxxxx", "checkout_session_id": "cs_xxxxx", "amount": 1099.00, "currency": "usd", "expires_at": "2026-05-12T01:00:00Z" } }
POST /api/v1/payments?action=save-settings
Save payment method toggles and invoice settings for the tenant.
FieldTypeDescription
payment_methodsobjectPayment method enable/disable toggles. Accepted keys: accept_card, accept_bank, accept_manual (e.g. {"accept_card": true, "accept_bank": false, "accept_manual": true})
invoice_settingsobjectInvoice settings. Accepted keys: invoice_prefix and payment_terms_days
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": { "accept_card": true, "accept_bank": false, "accept_manual": true }, "invoice_settings": { "invoice_prefix": "INV-", "payment_terms_days": 30 } }'
Response (200)
{ "error": false, "success": true, "data": { "message": "Payment settings saved" } }
POST /api/v1/payments?action=connect-provider
Initiate payment account 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-provider \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{}'
Response (200)
{ "error": false, "success": true, "data": { "url": "https://connect.stripe.com/setup/e/acct_xxxxx/xxxxx", "account_id": "acct_xxxxx" } }
POST /api/v1/payments?action=disconnect-provider
Disconnect the tenant's payment account from Salesbooth. Disables payment provider-based payment processing until reconnected.
Example
curl -X POST https://api.salesbooth.com/v1/payments?action=disconnect-provider \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{}'
Response (200)
{ "error": false, "success": true, "data": { "message": "payment 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 │ │ │ └───────────┘ │ └───────────────────────────────────────────────────────────────────────────┘
StatusDescription
activeSubscription is renewing normally. Metered usage is accumulating for the current cycle.
pausedNo renewals will occur. Usage meters stopped. Resume restarts from pause date.
past_dueMost recent renewal payment failed. Subscription continues in grace period; retry payment to return to active.
suspendedGrace period expired without successful payment. Service should be suspended. Requires manual payment recovery.
cancelledSubscription permanently cancelled. end_of_period: true cancels at cycle end; false cancels immediately.
GET /api/v1/subscriptions
List all subscriptions or retrieve a specific one. Pass action=analytics for subscription metrics.
ParameterTypeDescription
idstringRetrieve a specific subscription by deal ID
statusstringFilter: active, paused, cancelled, past_due, suspended
actionstringanalytics 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"
POST /api/v1/subscriptions?action=create action=create
Create a recurring subscription from a closed deal.
FieldTypeDescription
deal_id requiredstringThe deal to subscribe
action requiredstringQuery parameter — must be create
billing_cycle requiredstringmonthly, 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" }'
POST /api/v1/subscriptions?action=pause action=pause
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" }'
POST /api/v1/subscriptions?action=resume action=resume
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" }'
POST /api/v1/subscriptions?action=cancel action=cancel
Cancel a subscription. By default cancels immediately; pass end_of_period: true to cancel at the end of the current billing period.
FieldTypeDescription
deal_id requiredstringSubscription deal ID
action requiredstringQuery parameter — must be cancel
end_of_periodbooleanIf true, cancels at end of the billing period. Defaults to false (immediate cancellation).
reasonstringOptional cancellation reason for record-keeping
proratebooleanWhether 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 }'
POST /api/v1/subscriptions?action=renew action=renew
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" }'
POST /api/v1/subscriptions?action=retry-payment action=retry-payment
Retry a failed renewal payment for a past_due subscription. Optionally extends the grace period.
FieldTypeDescription
deal_id requiredstringSubscription deal ID
action requiredstringQuery parameter — must be retry-payment
grace_daysintegerAdditional 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 }'
POST /api/v1/subscriptions?action=change action=change
Upgrade or downgrade a subscription immediately by replacing its line items. The response includes proration details for the remaining current period.
FieldTypeDescription
deal_id requiredstringSubscription deal ID
action requiredstringQuery parameter — must be change
line_items requiredarrayNew line items — each item requires product_id (string), name (string), and unit_price (number ≥0); quantity (number ≥1, default 1) is optional
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", "name": "Enterprise Plan", "quantity": 1, "unit_price": 299.00 } ] }'
GET /api/v1/subscriptions?id={deal_id}&action=usage_summary
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, "success": true, "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" } }
POST /api/v1/subscriptions?action=change-cycle action=change-cycle
Change the billing cycle for an active subscription immediately. The response includes proration details and the recalculated next billing date.
FieldTypeDescription
deal_id requiredstringSubscription deal ID
action requiredstringQuery parameter — must be change-cycle
billing_cycle requiredstringmonthly, 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.

POST /api/v1/subscriptions?action=add-meter action=add-meter
Add a usage meter to a subscription. Define the metric, unit, and price per unit.
FieldTypeDescription
deal_id requiredstringSubscription deal ID
action requiredstringQuery parameter — must be add-meter
metric_name requiredstringMetric identifier (e.g. api_calls, seats, storage_gb)
billing_modelstringBilling model: per_unit, tiered, or volume (default: per_unit)
unit_pricenumberPrice charged per unit for per_unit billing; defaults to 0 when omitted. tiered and volume meters use tiers.
included_quantityintegerIncluded free units per billing period (default: 0)
tiersarrayPricing tiers for tiered or volume billing models
currencystringCurrency code (e.g. USD); defaults to the subscription currency
Example — add API call meter
curl -X POST "https://api.salesbooth.com/v1/subscriptions?action=add-meter" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "deal_id": "deal_abc123", "metric_name": "api_calls", "billing_model": "per_unit", "unit_price": 0.001, "included_quantity": 10000, "currency": "USD" }'
POST /api/v1/subscriptions?action=remove-meter action=remove-meter
Remove a usage meter from a subscription. Accumulated usage for the current billing period is discarded.
FieldTypeDescription
deal_idstringSubscription deal ID (not required; meter is identified by meter_id)
action requiredstringQuery parameter — must be remove-meter
meter_id requiredstringID of the meter to remove
Example — remove API call meter
curl -X POST "https://api.salesbooth.com/v1/subscriptions?action=remove-meter" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "meter_id": "meter_xyz789" }'
POST /api/v1/subscriptions?action=record-usage action=record-usage
Record metered usage for a subscription. Call this from your application whenever a billable event occurs.
FieldTypeDescription
deal_id requiredstringSubscription deal ID
action requiredstringQuery parameter — must be record-usage
metric_name requiredstringMetric to record against (must exist on the subscription)
quantity requirednumberUnits consumed in this event
idempotency_keystringOptional idempotency key to prevent duplicate recording
metadataobjectOptional key-value metadata attached to this usage event
recordsarrayBatch 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?action=record-usage" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "deal_id": "deal_abc123", "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:readRequired for listing and retrieving staff members
staff:writeRequired for creating, updating, deactivating staff, and managing schedules
GET /api/v1/staff
List all active staff members, or retrieve a single staff member with their weekly schedule and assigned products.
ParameterTypeDescription
idstringRetrieve a specific staff member with schedule and assigned products
statusstringFilter by status: active, inactive
product_idstringFilter by assigned product
limitintegerMax results to return (default: 50)
offsetintegerPagination offset
Example
curl https://api.salesbooth.com/v1/staff \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
POST /api/v1/staff
Create a new staff member.
FieldTypeDescription
display_name requiredstringFull display name of the staff member
titlestringJob title or role (e.g. Senior Consultant)
biostringShort biography shown to customers
avatar_urlstringURL of the staff member’s profile photo
user_idstringLinked tenant user account ID
statusstringAccount status: active or inactive
max_daily_sessionsintegerMaximum bookings per day (1–100)
default_session_durationintegerDefault booking duration in minutes (5–480)
buffer_timeintegerBuffer between bookings in minutes (0–240)
timezonestringStaff member’s timezone (e.g. America/New_York)
metadataobjectArbitrary key/value metadata
schedulearrayWeekly availability schedule (up to 7 entries)
product_idsarrayProduct 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" }'
PATCH /api/v1/staff?id={staff_id}
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" }'
DELETE /api/v1/staff?id={staff_id}
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

POST /api/v1/staff?id={staff_id}&action=schedule
Set the weekly availability schedule for a staff member.
FieldTypeDescription
schedule requiredarrayArray 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" } ] }'
POST /api/v1/staff?id={staff_id}&action=override
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.
FieldTypeDescription
override_date requiredstringDate to override in YYYY-MM-DD format
is_availablebooleanWhether the staff member is available on this date (default: false)
start_timestringAvailability start time in HH:MM format — required when is_available is true
end_timestringAvailability end time in HH:MM format — required when is_available is true
reasonstringOptional 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" }'
PATCH /api/v1/staff?id={staff_id}&action=override&override_id={override_id}
Update an existing schedule override. Only the fields you supply are changed; omitted fields retain their current values.
Parameter / FieldTypeDescription
override_id requiredintegerID of the override to update (query string or request body)
is_availablebooleanUpdated availability flag
start_timestringUpdated start time in HH:MM format
end_timestringUpdated end time in HH:MM format
reasonstringUpdated 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" }'
DELETE /api/v1/staff?id={staff_id}&action=override&override_id={override_id}
Remove a date-specific schedule override, restoring the staff member’s regular weekly availability for that date.
ParameterTypeDescription
override_id requiredintegerID 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"
POST /api/v1/staff?id={staff_id}&action=assign_product
Assign a staff member to a bookable product so they appear as available during checkout.
FieldTypeDescription
product_id requiredstringThe 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" }'
DELETE /api/v1/staff?action=assign_product
Remove a product assignment from a staff member. The staff member will no longer appear as available for bookings of that product.
ParameterTypeDescription
id requiredstringStaff member ID
product_id requiredstringThe product to remove the assignment for
Example
curl -X DELETE "https://api.salesbooth.com/v1/staff?id=stf_xxxxx&action=assign_product&product_id=prod_xxxxx" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"

Bookings

Manage service bookings — hold time slots, confirm appointments, track attendance, and handle cancellations.

Required Scopes

bookings:readRequired for listing and retrieving bookings
bookings:writeRequired for creating, updating, and cancelling bookings
GET /api/v1/bookings
List bookings with optional filters, or retrieve a single booking by ID.
ParameterTypeDescription
idstringRetrieve a specific booking
statusstringFilter: held, confirmed, completed, cancelled, no_show
product_idstringFilter by product
staff_idstringFilter by staff member
deal_idstringFilter by associated deal
date_fromstring (date)Start date filter (YYYY-MM-DD)
date_tostring (date)End date filter (YYYY-MM-DD)
actionstringanalytics for booking metrics
periodstringAnalytics period (e.g. 7d, 30d, 90d; default: 30d). Used with action=analytics
limitintegerMax results (default: 50)
offsetintegerPagination offset
Example
curl https://api.salesbooth.com/v1/bookings?status=confirmed \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
POST /api/v1/bookings
Hold a booking slot for a customer. The booking starts in held status automatically and expires after 10 minutes if not confirmed via PATCH.
FieldTypeDescription
product_id requiredstringThe bookable product
staff_id requiredstringStaff member to assign the booking to
date requiredstring (date)Appointment date (YYYY-MM-DD)
start_time requiredstring (time)Appointment start time (HH:MM)
durationintegerDuration in minutes (5–480, default: 60)
customer_namestringCustomer display name
customer_emailstringCustomer email for confirmation
customer_phonestringCustomer phone number
notesstringBooking 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": "", "start_time": "10:00", "customer_name": "Alice Johnson", "customer_email": "alice@example.com" }'
Response (201)
{ "error": false, "success": true, "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": "Alice Johnson", "customer_email": "alice@example.com", "customer_phone": null, "booking_date": "", "start_time": "10:00", "end_time": "11:00", "status": "held", "hold_expires_at": "", "notes": null, "created_at": "", "updated_at": "" } } }
PATCH /api/v1/bookings?id={booking_id}
Transition a booking through its lifecycle. Send an action field with action-specific parameters.
FieldTypeDescription
action requiredstringconfirm, cancel, complete, no_show, or reschedule

action: confirm

FieldTypeDescription
deal_id requiredstringDeal to associate with this booking confirmation
line_item_idstringSpecific line item within the deal
customer_idstringCustomer to associate with this booking

action: cancel

FieldTypeDescription
reasonstringCancellation reason

action: complete / no_show

No additional fields required.

action: reschedule

FieldTypeDescription
product_id requiredstringBookable product for the new slot
staff_id requiredstringStaff member for the new slot
date requiredstringNew date in YYYY-MM-DD format
start_time requiredstringNew start time in HH:MM format
durationintegerDuration in minutes (5–480, default: 60)
customer_namestringCustomer display name
customer_emailstringCustomer email address
customer_phonestringCustomer phone number
notesstringBooking 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": "", "start_time": "14:00" }'
DELETE /api/v1/bookings?id={booking_id}
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.

GET /api/v1/availability
Return available time slots for a product on a specific date, or return a list of available dates for an entire month.
ParameterTypeDescription
product_id requiredstringBookable product to check
datestringDate in YYYY-MM-DD format — returns available time slots for that day
monthstringMonth in YYYY-MM format — returns all dates with availability in the month
staff_idstringOptional — filter slots for a specific staff member
Check a specific date
curl "https://api.salesbooth.com/v1/availability?product_id=prod_xxxxx&date=<future YYYY-MM-DD>" \ -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": "", "product_id": "prod_xxxxx" } }
Check a full month
curl "https://api.salesbooth.com/v1/availability?product_id=prod_xxxxx&month=<future YYYY-MM>" \ -H "Authorization: Bearer sb_pub_xxxxx"
Response (month)
{ "error": false, "success": true, "data": { "dates": ["", ""], "month": "", "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. Most write operations require agent:negotiate scope; the accept action requires the elevated agent:execute scope.

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 for propose, counter, reject, and suggest. The accept action requires agent:execute scope — accepting commits to deal terms and is treated as an execution action, not a negotiation action. An agent with only agent:negotiate scope will receive 403 authorization_error.insufficient_scope when calling accept.

Scope summary:

ActionRequired scope
proposeagent:negotiate
counteragent:negotiate
rejectagent:negotiate
suggestagent:negotiate
acceptagent:execute (elevated — commits deal terms)

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) │ └─────────────────────────────────────────────────────────────────────┘
StatusDescriptionNext valid actions
proposedInitial proposal submitted; awaiting response from other partycounter, accept, reject
counter_proposedCounter-proposal made; awaiting response from original proposercounter, accept, reject
acceptedTerms agreed — deal terms updated to reflect final negotiated values(terminal)
rejectedProposal rejected; no further rounds(terminal)
expiredProposal TTL elapsed without response(terminal)
GET /api/v1/deal-negotiations?deal_id={deal_id}
Get the full negotiation history for a deal, including all proposals, counter-proposals, and outcomes.
ParameterTypeDescription
deal_id requiredstringThe 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, "success": true, "data": { "deal_id": "deal_abc123", "total_rounds": 2, "rounds": [ { "negotiation_id": "neg_111aaa", "deal_id": "deal_abc123", "round_number": 1, "proposer_type": "agent", "proposer_id": "agent_xyz", "proposed_terms": { "discount_percent": 15, "quantity": 10 }, "message": "Volume order — requesting 15% discount", "status": "proposal", "expires_at": "2026-03-16T10:00:00Z", "created_at": "2026-03-09T10:00:00Z" }, { "negotiation_id": "neg_222bbb", "deal_id": "deal_abc123", "round_number": 2, "proposer_type": "merchant", "proposer_id": "user_merchant1", "proposed_terms": { "discount_percent": 10, "quantity": 10 }, "message": "We can offer 10% for this volume", "status": "counter", "expires_at": "2026-03-18T10:00:00Z", "created_at": "2026-03-09T10:05:00Z" } ] } }
GET /api/v1/deal-negotiations?deal_id={deal_id}&action=intelligence
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, "success": true, "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 } }
POST /api/v1/deal-negotiations?action={action}&deal_id={deal_id}
Submit a negotiation action: propose, counter, accept, reject, or suggest. Use the dedicated action=suggest card below for the AI suggestion response details. Note: accept requires agent:execute scope; all other actions require agent:negotiate scope.
FieldTypeDescription
action requiredstringpropose, counter, accept, reject, suggest. The accept action requires agent:execute scope; others require agent:negotiate.
deal_id requiredstringThe deal identifier
proposed_termsobjectTerms to propose (required for propose and counter). Free-form key/value pairs: e.g. discount_percent, quantity, payment_terms
current_termsobjectCurrent terms to analyse when action=suggest. If omitted, the latest round terms are used automatically.
messagestringOptional message to accompany the proposal
expires_atstringISO 8601 expiry for this round (defaults to 7 days)
reasonstringRejection 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" }'
POST /api/v1/deal-negotiations?action=suggest&deal_id={deal_id}
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.
FieldTypeDescription
deal_id requiredstringThe deal identifier
current_termsobjectThe 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, "success": true, "data": { "suggestions": [ { "type": "split_difference", "recommended_terms": { "discount_percent": 10, "payment_terms": "net_15", "custom_terms": { "proposed_total": 2250, "original_total": 2500 } }, "confidence": 82, "rationale": "10% discount with net-15 closes 69% of similar deals; net-30 adds payment risk", "risk_level": "low", "risk_assessment": "Low concession risk because the counter preserves margin while improving close probability." }, { "type": "discount_aggressive", "recommended_terms": { "discount_percent": 7, "payment_terms": "net_7", "custom_terms": { "proposed_total": 2325, "original_total": 2500 } }, "confidence": 61, "rationale": "Maximum margin protection; 41% acceptance rate at this price point", "risk_level": "medium", "risk_assessment": "Higher rejection risk, but protects margin and shortens payment terms." } ], "deal_id": "deal_abc123", "suggestion_id": "sugg_abc123", "data_quality": "high", "historical_deals": 52, "currency": "USD", "reference_price": 2500, "current_proposed_price": 2125 } }

Deal Templates

Reusable deal templates for programmatic offer generation. Create templates with pre-defined line items and terms, then instantiate them into real deals.

GET /api/v1/deal-templates
List deal templates with optional filters.
ParameterTypeDescription
idstringRetrieve a specific template
is_activestringFilter: 1 (active, default), 0 (inactive)
searchstringSearch by name or description
limitintegerMax results, 1–100 (default: 50)
offsetintegerPagination offset
Example
curl https://api.salesbooth.com/v1/deal-templates \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
POST /api/v1/deal-templates
Create a new deal template.
FieldTypeDescription
name requiredstringTemplate name
descriptionstringTemplate description
template_data requiredobjectTemplate content: line_items, discounts, terms, currency, etc.
is_activebooleanWhether the template is active (default: true)
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", "template_data": { "category": "enterprise", "default_terms": { "currency": "USD", "tax_rate": 0.10 }, "line_items": [ { "product_id": "prod_xxxxx", "quantity": 1, "unit_price": 999.00 } ] } }'
POST /api/v1/deal-templates?id={template_id}&action=create-deal
Instantiate a template into a real deal. Creates a deal with the template’s pre-defined line items and terms.
FieldTypeDescription
customer_idstringCustomer for the new deal
currencystringOptional top-level currency override
tax_ratestringOptional top-level tax rate override
titlestringOptional top-level title override
descriptionstringOptional top-level description override
presentation_currencystringOptional top-level presentation currency override
settlement_currencystringOptional top-level settlement currency override
metadataobjectOptional metadata merged into the template metadata for the created deal
line_itemsarrayOptional per-line-item overrides keyed by template line-item index
discountsarrayOptional replacement discounts for the instantiated deal
termsobjectOptional replacement terms for the instantiated deal
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" }'
POST /api/v1/deal-templates?id={template_id}&action=clone
Clone an existing deal template into a new template. You can optionally override the cloned template’s name or description.
FieldTypeDescription
namestringOptional name override for the cloned template
descriptionstringOptional description override for the cloned template
Example
curl -X POST "https://api.salesbooth.com/v1/deal-templates?id=dtpl_xxxxx&action=clone" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "name": "Copy of Enterprise Starter Pack" }'
PATCH /api/v1/deal-templates?id={template_id}
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 /api/v1/deal-templates?id={template_id}
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"
GET /api/v1/deal-templates?id={template_id}&action=versions
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": { "template_id": "dtpl_xxxxx", "current_version": 3, "versions": [ { "version_number": 3, "name": "Enterprise Starter Pack", "description": "Updated pricing tiers", "changed_by": 123, "change_summary": "Updated pricing", "created_at": "2026-05-10T12:00:00Z" }, { "version_number": 2, "name": "Enterprise Starter Pack", "description": "Added support option", "changed_by": 123, "change_summary": "Added line item", "created_at": "2026-04-22T09:15:00Z" }, { "version_number": 1, "name": "Enterprise Starter Pack", "description": "Initial version", "changed_by": 123, "change_summary": "Initial version", "created_at": "2026-04-01T08:00:00Z" } ] } }
GET /api/v1/deal-templates?id={template_id}&action=version&version=N
Retrieve the full snapshot of a deal template at a specific version number.
ParameterTypeDescription
version requiredintegerVersion 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"
GET /api/v1/deal-templates?id={template_id}&action=diff&from=N&to=M
Compare two versions of a deal template and return a field-by-field diff of what changed between them.
ParameterTypeDescription
from requiredintegerEarlier version number
to requiredintegerLater 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"
POST /api/v1/deal-templates?id={template_id}&action=rollback
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.
FieldTypeDescription
version requiredintegerVersion 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.

GET /api/v1/delegations
List delegations you have created, or retrieve a specific delegation by ID. Use action=verify to check validity and remaining budget.
ParameterTypeDescription
idstringRetrieve a specific delegation
actionstringverify — check validity and budget; summary — dashboard summary; pending — incoming proposals (agent key only)
limitintegerMax results (default: 50)
offsetintegerPagination 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": "", "grantee_key_id": "key_agent_xxxxx" } }
GET /api/v1/delegations?action=check
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": "" } }
GET /api/v1/delegations?action=spending&id={delegation_id}
Retrieve spending totals and limit utilisation for a delegation. Shows per-transaction, daily, and monthly usage against configured caps.
ParameterTypeDescription
id requiredstringDelegation 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, "reserved_this_month": 1200.00, "max_daily_amount": 25000.00, "max_monthly_amount": null, "available_today": 20750.00, "available_this_month": null, "max_transaction_amount": 5000.00, "daily_utilization_pct": 17.0, "monthly_utilization_pct": null } }
GET /api/v1/delegations?action=analytics&id={delegation_id}
Retrieve per-delegation analytics including spending breakdown, deals created, ROI metrics, and a 30-day spending chart.
ParameterTypeDescription
id requiredstringDelegation 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": { "delegation_id": "del_xxxxx", "grantee_agent_key_id": "key_agent_xxxxx", "allowed_actions": ["deals:read", "deals:write", "agent:negotiate"], "max_daily_amount": "25000.00", "spent_today": "3750.00", "reserved_today": "500.00", "available_today": "20750.00" }, "spending": { "spent_today": "3750.00", "spent_this_week": "12850.00", "spent_this_month": "48200.00", "reserved_today": "500.00", "lifetime_spend": "62400.00", "avg_daily_spend": "4457.14", "daily_utilization_pct": 17, "monthly_utilization_pct": null }, "burn_rate": { "monthly_daily_rate": "1606.67", "monthly_days_remaining": null, "projected_exhaustion_date": null, "days_in_month": 30, "days_elapsed": 30 }, "deals": { "count": 14, "total_value": "62400.00", "close_rate": 0.8571, "items": [ { "deal_id": "deal_xxxxx", "title": "Annual SaaS plan", "status": "signed", "value": "5200.00", "customer_id": "cus_xxxxx", "created_at": "2026-04-16 10:30:00" } ] }, "roi": { "deal_value": "62400.00", "platform_cost": "62400.00", "roi_ratio": 1 }, "chart": [ { "day": "2026-04-16", "spend": 4200 } ], "activity": { "total": 3, "offset": 0, "limit": 100, "items": [ { "action": "deal_created", "entity_type": "deal", "entity_id": "deal_xxxxx", "created_at": "2026-04-16 10:30:00", "outcome": "success" } ] } } }
GET /api/v1/delegations?action=summary
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_delegations": 3, "total_spent_today": "3750.00", "total_reserved_today": "500.00", "approaching_limit": 1, "recent_actions": [ { "action": "deal_created", "entity_id": "del_xxxxx", "created_at": "2026-04-16 10:30:00" } ] } }
GET /api/v1/delegations?action=pending
List pending delegation proposals targeting the calling agent key. Requires agent API key auth and delegations:read scope.
ParameterTypeDescription
limitintegerMax results (default: 50, max: 100)
offsetintegerPagination offset (default: 0)
Example
curl "https://api.salesbooth.com/v1/delegations?action=pending" \ -H "Authorization: Bearer sb_agent_key_do_not_use"
Response
{ "error": false, "success": true, "data": { "proposals": [ { "id": "dprop_xxxxx", "status": "pending", "proposer_api_key_id": "key_agent_aaaaa", "target_api_key_id": "key_agent_bbbbb", "proposer_trust_level": 2, "proposer_trust_label": "trusted" } ], "pagination": { "total": 1, "limit": 50, "offset": 0, "count": 1 } } }
GET /api/v1/delegations?action=proposal&id={proposal_id}
Retrieve details of a specific delegation proposal including its current status, negotiation history, and proposed terms.
ParameterTypeDescription
id requiredstringDelegation 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": "" } }
GET /api/v1/delegations?action=activity&id={delegation_id}
Retrieve a paginated, filterable audit trail of all actions taken under a delegation. Supports date range and action/entity type filtering.
ParameterTypeDescription
id requiredstringDelegation ID
from_datestringFilter from date (ISO 8601)
to_datestringFilter to date (ISO 8601)
action_typestringFilter by action type (e.g. deal_created, deal_signed)
entity_typestringFilter by entity type (e.g. deal, customer)
limitintegerMax results (default: 50)
offsetintegerPagination 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": { "items": [ { "action": "deal_created", "entity_type": "deal", "entity_id": "deal_xxxxx", "created_at": "2026-04-12T14:30:00Z", "outcome": "success", "details": {} } ], "total": 42, "limit": 50, "offset": 0 } }
POST /api/v1/delegations
Create a new delegation granting an agent API key a subset of your permissions with optional spending limits.

Note: Replace example expires_at values with a real future timestamp before sending a request.

FieldTypeDescription
grantee_agent_key_id requiredstringThe agent API key ID to delegate to
allowed_actions requiredarrayPermitted actions (scope-based): deals:read, deals:write, agent:negotiate, deals:sign, customers:read, customers:write
max_transaction_amountnumberPer-transaction spending cap (null = no limit)
max_daily_amountnumberDaily spending cap (resets at midnight UTC)
max_monthly_amountnumberMonthly spending cap (resets on the 1st)
expires_atstringDelegation expiry (ISO 8601, must be in the future)
descriptionstringHuman-readable description of the delegation purpose (max 500 chars)
approval_thresholdnumberTransaction amount above which approval is required
approval_stepsobjectMulti-step approval workflow configuration
approval_timeoutintegerHours before pending approval auto-expires (0–720)
auto_approve_policyobjectConditions under which transactions are auto-approved
alert_threshold_pctintegerSpending alert when daily/monthly usage reaches this percentage (1–100)
signing_authority_acknowledgedbooleanRequired 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": "" }'
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": "", "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 } }
PUT /api/v1/delegations?id={delegation_id}
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": "" }'
DELETE /api/v1/delegations?id={delegation_id}
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.

GET /api/v1/delegations/proposals
List pending delegation proposals targeting this agent. Requires agent API key auth and delegations:read scope.
ParameterTypeDescription
limitintegerMax results (default: 50, max: 100)
offsetintegerPagination offset (default: 0)
Example
curl "https://api.salesbooth.com/v1/delegations/proposals" \ -H "Authorization: Bearer sb_agent_key_do_not_use"
Response
{ "error": false, "success": true, "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": "", "created_at": "2026-03-16T10:00:00Z" } ], "pagination": { "total": 1, "limit": 50, "offset": 0 } } }
POST /api/v1/delegations/proposals
Propose a delegation to a target agent. Requires trust level 2+ and the delegate action in the proposer’s own delegation scope.
FieldTypeDescription
target_api_key_id requiredstringAPI key ID of the target agent
proposed_actions requiredarrayActions being proposed (e.g. discover, negotiate)
max_transaction_amountnumberProposed per-transaction spending cap
max_daily_amountnumberProposed daily spending cap
max_monthly_amountnumberProposed monthly spending cap
proposed_duration_hoursintegerDelegation duration from acceptance (default: 168 = 1 week)
messagestringOptional 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": "", "created_at": "2026-03-16T10:00:00Z" } }
POST /api/v1/delegations/proposals/{id}/accept
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"] } } }
POST /api/v1/delegations/proposals/{id}/reject
Reject an incoming delegation proposal. The proposal is marked as rejected and no delegation is created.
FieldTypeDescription
reasonstringOptional 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" }'
POST /api/v1/delegations/proposals/{id}/counter
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.
FieldTypeDescription
proposed_actions requiredarrayCounter-proposed actions (must be subset of original)
max_transaction_amountnumberCounter-proposed per-transaction cap
max_daily_amountnumberCounter-proposed daily cap
max_monthly_amountnumberCounter-proposed monthly cap
proposed_duration_hoursintegerCounter-proposed duration in hours
messagestringOptional 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, "success": true, "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": "", "created_at": "2026-03-16T10:05:00Z" } }

Using a Delegation

Pass the X-Delegation-ID header to operate within a delegation’s constraints. Draft POST /deals creation validates delegation presence and scope, while configured deal creation computes the estimated total before enforcing max_transaction_amount, daily, and monthly budget caps.

curl -X POST "https://api.salesbooth.com/v1/deals?action=create-configured" \ -H "Authorization: Bearer sb_agent_key_do_not_use" \ -H "X-Delegation-ID: del_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "title": "Kitchen renovation quote", "customer": { "name": "Jordan Lee", "email": "jordan@example.com" }, "items": [ { "product_id": "prod_kitchen_package", "name": "Kitchen renovation package", "quantity": 1, "unit_price": 6500.00 } ], "currency": "USD" }' # If the computed deal total exceeds 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.

GET /api/v1/product-families
List product families or retrieve a specific family.
ParameterTypeDescription
idstringRetrieve a specific family
statusstringFilter: active, archived
searchstringSearch by name
Example
curl https://api.salesbooth.com/v1/product-families \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
POST /api/v1/product-families
Create a new product family.
FieldTypeDescription
name requiredstringFamily name
descriptionstringFamily description
slugstringURL-friendly slug
sort_orderintegerDisplay order
image_urlstringFamily image URL
statusstringactive 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" }'
PATCH /api/v1/product-families?id={family_id}
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" }'
DELETE /api/v1/product-families?id={family_id}
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.

GET /api/v1/option-groups
List option groups or retrieve a specific group with its options.
ParameterTypeDescription
idstringRetrieve a specific group
statusstringFilter: active, archived
searchstringSearch by name
include_optionsbooleanInclude 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"
POST /api/v1/option-groups
Create a new option group.
FieldTypeDescription
name requiredstringGroup name (e.g. “Colour”, “Storage”)
descriptionstringGroup description
selection_typestringsingle or multiple
is_requiredbooleanWhether selection is required
min_selectionsintegerMinimum options the customer must select (0–100)
max_selectionsintegerMaximum options the customer can select (0–100)
display_stylestringcards, dropdown, pills, swatches, checkboxes
sort_orderintegerDisplay 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

POST /api/v1/option-groups?id={group_id}&action=options
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 }'
PATCH /api/v1/option-groups?id={group_id}
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" }'
DELETE /api/v1/option-groups?id={group_id}
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.

GET /api/v1/bundle-rules
List bundle pricing rules, optionally filtered by product.
ParameterTypeDescription
idstringRetrieve a specific rule
product_idstringFilter by product
is_activebooleanFilter 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"
POST /api/v1/bundle-rules
Create a bundle pricing rule.
FieldTypeDescription
name requiredstringRule name
product_idstringOptional product scope; supply to limit this rule to a specific product
option_ids requiredarrayOption IDs that trigger the bundle
discount_type requiredstringpercent or fixed
discount_value requirednumberDiscount amount (percent or fixed)
min_optionsintegerMinimum 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": "percent", "discount_value": 15, "min_options": 3 }'
PATCH /api/v1/bundle-rules?id={rule_id}
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 /api/v1/bundle-rules?id={rule_id}
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.

GET /api/v1/compatibility-rules
List compatibility rules, optionally filtered by product or rule type.
ParameterTypeDescription
idstringRetrieve a specific rule
product_idstringFilter by product
rule_typestringFilter: requires, excludes, includes_price
source_option_idstringFilter 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"
POST /api/v1/compatibility-rules
Create a compatibility rule between two options.
FieldTypeDescription
source_option_id requiredstringThe triggering option
target_option_id requiredstringThe affected option
rule_type requiredstringrequires, excludes, or includes_price
product_idstringOptional product scope; supply to limit this rule to a specific product
messagestringUser-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" }'
PATCH /api/v1/compatibility-rules?id={rule_id}
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 /api/v1/compatibility-rules?id={rule_id}
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 /api/v1/product-option-groups?product_id={product_id}
Get linked option groups and per-product option availability for a product.
ParameterTypeDescription
product_id requiredstringThe product identifier
Example
curl "https://api.salesbooth.com/v1/product-option-groups?product_id=prod_xxxxx" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
POST /api/v1/product-option-groups
Link an option group to a product, or set per-option availability overrides.
FieldTypeDescription
product_id requiredstringThe product identifier
group_idstringOption group to link (required when not setting availability)
sort_order_overrideintegerOverride display order for this product
is_required_overridebooleanOverride whether the group is required
actionstringavailability 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 }'
PATCH /api/v1/product-option-groups?product_id={product_id}&group_id={group_id}
Update link overrides or option availability for a product–option group association.
ParameterTypeDescription
product_id requiredstringThe product identifier
group_idstringOption group to update on the default link update path
option_idstringOption to update when action=availability
actionstringavailability to update per-option availability instead of link overrides
Example — Update link overrides
curl -X PATCH "https://api.salesbooth.com/v1/product-option-groups?product_id=prod_xxxxx&group_id=grp_xxxxx" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "sort_order_override": 2 }'
Example — Update availability override
curl -X PATCH "https://api.salesbooth.com/v1/product-option-groups?product_id=prod_xxxxx&option_id=opt_xxxxx&action=availability" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "is_available": false, "price_modifier_override": 25 }'
DELETE /api/v1/product-option-groups?product_id={product_id}&group_id={group_id}
Unlink an option group from a product, or remove a per-option availability override.
ParameterTypeDescription
product_id requiredstringThe product identifier
group_idstringOption group to unlink on the default unlink path
option_idstringOption availability override to remove when action=availability
actionstringavailability to remove a per-option availability override
Example — Unlink option group
curl -X DELETE "https://api.salesbooth.com/v1/product-option-groups?product_id=prod_xxxxx&group_id=grp_xxxxx" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
Example — Remove availability override
curl -X DELETE "https://api.salesbooth.com/v1/product-option-groups?product_id=prod_xxxxx&option_id=opt_xxxxx&action=availability" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"

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 /api/v1/product-rules?product_id={product_id}
Get all active compatibility and bundle rules for a product in a single request.
ParameterTypeDescription
product_id requiredstringThe 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"
POST /api/v1/product-rules?product_id={product_id}&action=validate
Validate a configuration — a set of selected option IDs — against all rules for a product. Returns any violations with human-readable messages.
FieldTypeDescription
product_id requiredstringQuery parameter for the product identifier
action requiredstringQuery parameter that must be validate
option_ids requiredarrayArray of selected option IDs to validate
Example
curl -X POST "https://api.salesbooth.com/v1/product-rules?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_ssd_512", "opt_ram_32gb"] }'
Response
{ "error": false, "success": true, "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 /api/v1/configuration?product_id={product_id}
Get the full configuration schema for a product, including option groups, compatibility rules, and bundle rules.
ParameterTypeDescription
product_id requiredstringProduct identifier
Example
curl https://api.salesbooth.com/v1/configuration?product_id=prod_xxxxx \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
GET /api/v1/configuration?action=families
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"
POST /api/v1/configuration?product_id={product_id}&action=validate
Validate a set of selected options against the product’s configuration rules.
FieldTypeDescription
option_ids requiredarrayArray 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, "success": true, "data": { "valid": true, "violations": [], "bundles_applied": ["Full Suite Bundle"] } }
POST /api/v1/configuration?product_id={product_id}&action=price
Calculate pricing for a configuration, including bundle discounts and option price modifiers.
FieldTypeDescription
option_ids requiredarrayArray 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, "success": true, "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.

GET /api/v1/webhooks
List all registered webhooks. Pass ?id= to retrieve a single webhook by ID.
FieldTypeDescription
idstringIf provided, returns a single webhook object instead of a list
statusstringFilter by status: active, paused, or failed
limitintegerNumber of results per page (offset-based pagination)
offsetintegerNumber of results to skip (offset-based pagination)
afterstringReturn results after this cursor (cursor-based pagination)
beforestringReturn results before this cursor (cursor-based pagination)
sortstringSort order for results (e.g. created_at:desc)
POST /api/v1/webhooks
Register a new webhook.
FieldTypeDescription
url requiredstringHTTPS endpoint URL to receive webhook events
events requiredarrayEvent types to subscribe to (e.g. deal.created)
descriptionstringOptional 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"] }'
Response
{ "error": false, "success": true, "data": { "webhook": { "webhook_id": "wh_abc123", "url": "https://myapp.com/webhooks/salesbooth", "events": ["deal.created"], "description": null, "status": "active", "secret": "whsec_abc123...", "created_at": "2026-05-23T10:00:00Z" } } }
Important: The secret field is only returned once — on creation. Store it securely immediately; it cannot be retrieved again. Use it to verify the X-Salesbooth-Signature header on incoming webhook requests. To rotate the secret, call POST /api/v1/webhooks/rotate_secret?id={webhook_id}.
New webhooks start as active by default. To pause a webhook, use PATCH with "status": "paused".
PATCH /api/v1/webhooks?id={webhook_id}
Update an existing webhook’s URL, subscribed events, status, or description.
FieldDescription
urlNew endpoint URL
eventsArray of event type strings to subscribe to
statusactive or paused
descriptionHuman-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"] }'
DELETE /api/v1/webhooks?id={webhook_id}
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"
POST /api/v1/webhooks/rotate_secret?id={webhook_id}
Rotate the signing secret for a webhook.
GET /api/v1/webhooks/deliveries
List delivery attempts for a specific webhook with filtering and pagination.
ParameterDescription
id requiredWebhook ID to retrieve deliveries for
statusFilter by delivery status: pending, success, or failed
event_typeFilter by event type (e.g. deal.created)
limitNumber of results to return (default 50, max 100)
offsetPagination 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 } } }
GET /api/v1/webhooks/events
List webhook event history with cursor-based pagination. Use since_sequence or since_timestamp to resume from a known position.
ParameterDescription
since_sequenceReturn events after this sequence number (cursor-based pagination)
since_timestampReturn events after this ISO 8601 timestamp
event_typeFilter by event type (e.g. deal.created)
statusFilter by delivery status: pending, delivered, partially_delivered, or failed
limitNumber 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 } } }
GET /api/v1/webhooks/dead_letter
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.
ParameterDescription
event_typeFilter by event type
webhook_idFilter by webhook ID
limitNumber of results to return (default 50)
offsetPagination 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": 3, "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 } } }
POST /api/v1/webhooks/test
Send a test event to a webhook endpoint to verify connectivity and your handler logic.
FieldTypeDescription
id requiredqueryWebhook ID to send the test event to
event_typebodyEvent 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" } }
POST /api/v1/webhooks/replay
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.
FieldDescription
webhook_id requiredTarget webhook to replay events to
since_sequenceReplay events after this sequence number
since_timestampReplay events after this ISO 8601 timestamp
event_typeOnly 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" } ] } }
POST /api/v1/webhooks/retry
Manually retry a specific failed delivery. Resets the delivery to pending and attempts immediate re-delivery.
FieldDescription
delivery_id requiredID 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": 1, "response_code": 200, "error_message": null, "retried_at": "2026-03-09T18:00:00Z" } } }
POST /api/v1/webhooks/cleanup
Delete delivered webhook events older than the retention period. Safe to call from a cron job.
FieldDescription
retention_daysDays of events to retain (default 30)
batch_sizeMaximum 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.createdA new deal was created
deal.updatedA deal's fields were updated
deal.status_changedA deal transitioned to a new status
deal.closedA deal was closed
deal.fulfilledA deal was fulfilled
deal.expiredA deal expired without being completed
deal.unsignedA deal's signature was removed
deal.signature_addedA signature was added to a deal
deal.signature_timeoutA deal's signature request timed out
deal.item_addedA line item was added to a deal
deal.item_removedA line item was removed from a deal
deal.item_updatedA line item on a deal was updated
deal.discount_appliedA discount was applied to a deal
deal.partially_acceptedA deal was partially accepted by the customer
deal.created_configuredA deal was created from a saved product configuration
deal.payment_receivedA payment was received for a deal
deal.payment_failedA payment attempt failed
deal.payment_refundedA payment was refunded (full or partial)
deal.payment_overdueA payment is overdue
deal.settlement_createdA settlement was created for a deal
deal.settlement_initiatedA settlement was initiated
deal.settlement_completedA settlement completed successfully
deal.settlement_failedA settlement failed
deal.settlement_all_completedAll settlements for a deal completed
deal.participant_invitedA participant was invited to a deal
deal.participant_acceptedA participant accepted their deal invitation
deal.participant_withdrawnA participant withdrew from a deal
deal.participant_completedA participant completed their deal obligations
Negotiation Events — Legacy (deal.*) Maintained for backward compatibility. Both families fire simultaneously.
deal.negotiation_proposedA negotiation proposal was made (minimal payload)
deal.negotiation_counter_proposedA counter-proposal was made (minimal payload)
deal.negotiation_acceptedA negotiation proposal was accepted (minimal payload)
deal.negotiation_rejectedA negotiation proposal was rejected (minimal payload)
Negotiation Events — Current (negotiation.*) Richer payloads. Prefer these for new integrations.
negotiation.proposedInitial proposal submitted — includes proposer, terms, and expires_at
negotiation.counteredCounter-proposal made — includes round_number, previous_terms, and new_terms for diffing
negotiation.acceptedProposal accepted — includes final_terms and total_rounds
negotiation.rejectedProposal rejected — includes reason and round_number
negotiation.expiredA negotiation round expired without resolution
negotiation.suggestion_generatedAI generated a negotiation suggestion
Contract Events
contract.signedA contract was signed
contract.activatedA contract was activated
contract.terminatedA contract was terminated
contract.tamper_detectedA tamper attempt was detected on a contract
contract.auto_renewedA contract was automatically renewed
contract.renewal_failedA contract auto-renewal attempt failed
contract.renewal_opted_outA customer opted out of contract auto-renewal
contract.renewal_upcomingA contract renewal is approaching
Subscription Events
subscription.createdA subscription was created
subscription.renewedA subscription was renewed
subscription.renewal_upcomingA subscription renewal is approaching
subscription.pausedA subscription was paused
subscription.resumedA paused subscription was resumed
subscription.cancelledA subscription was cancelled
subscription.upgradedA subscription was upgraded to a higher tier
subscription.downgradedA subscription was downgraded to a lower tier
subscription.changedA subscription was modified
subscription.past_dueA subscription payment is past due
subscription.suspendedA subscription was suspended due to non-payment
subscription.cycle_changedA subscription billing cycle was changed
subscription.payment_failedA subscription payment attempt failed
subscription.payment_retriedA failed subscription payment was retried
subscription.proration_creditA proration credit was applied to a subscription
subscription.meter_addedA usage meter was added to a subscription
subscription.meter_removedA usage meter was removed from a subscription
subscription.usage_recordedUsage was recorded against a subscription meter
subscription.usage_charges_appliedUsage charges were applied to a subscription
Customer Events
customer.createdA new customer was created
customer.updatedA customer record was updated
customer.deletedA customer was deleted
Booking Events
booking.createdA new booking was created
booking.cancelledA booking was cancelled
booking.completedA booking was completed
booking.no_showA customer did not show up for a booking
booking.heldA booking slot was placed on hold
booking.hold_expiredA booking hold expired without confirmation
booking.rescheduledA booking was rescheduled to a new time
Billing Events
billing.credit_addedCredits were added to the account balance
billing.credit_deductedCredits were deducted from the account balance
billing.auto_topupAn automatic top-up was triggered
billing.low_balanceAccount credit balance dropped below the threshold
billing.widget_degradedThe widget entered degraded mode due to insufficient credits
Delegation Events
delegation.proposedA delegation proposal was submitted
delegation.acceptedA delegation proposal was accepted
delegation.rejectedA delegation proposal was rejected
delegation.counteredA counter-proposal was made to a delegation
delegation.grantedA delegation was granted to an agent
delegation.revokedA delegation was revoked
delegation.expiredA delegation expired
delegation.budget_warningA delegation is approaching its budget limit
Agent Events
agent.approval_requiredAn agent action requires human approval
agent.approval_resentAn approval request was resent
agent.approval_escalatedAn approval request was escalated
agent.anomaly_detectedAnomalous agent behaviour was detected
agent.spending_ceilingAn agent reached its spending ceiling
agent.trust_cap_exceededAn agent exceeded its trust cap
agent.trust.level_changedAn agent's trust level changed
agent.trust.abuse_detectedAbuse was detected from a trusted agent
agent.trust.decay_warningAn agent's trust score is decaying
agent.trust.credential_issuedA trust credential was issued to an agent
agent.trust.credential_presentedAn agent presented a trust credential
agent.trust.credential_revokedAn agent's trust credential was revoked
Agent Workflow Events
agent.workflow.plannedAn agent workflow plan was created
agent.workflow.approvedAn agent workflow was approved to proceed
agent.workflow.completedAn agent workflow completed successfully
agent.workflow.failedAn agent workflow failed
agent.workflow.cancelledAn agent workflow was cancelled
agent.workflow.degradedAn agent workflow entered degraded mode
agent.workflow.step_completedA step in an agent workflow completed
agent.workflow.step_retriedA workflow step was retried
agent.workflow.dead_letteredA workflow step was moved to the dead-letter queue
Escrow Events
escrow.createdAn escrow was created
escrow.releasedAn escrow was released
escrow.refundedAn escrow was refunded
escrow.condition_fulfilledAn escrow condition was fulfilled
escrow.reauthorization_pendingAn escrow requires reauthorization
escrow.reauthorizedAn escrow was successfully reauthorized
escrow.reauthorization_failedAn escrow reauthorization attempt failed
Federation Events
federation.settlement_completedA cross-tenant federated settlement completed
federation.settlement_failedA cross-tenant federated settlement failed
federation.escrow_disputedA federated escrow was disputed
federation.escrow_expiredA federated escrow expired
Product & Catalogue Events
product_family.createdA product family was created
product_family.updatedA product family was updated
product_family.deletedA product family was deleted
option_group.createdAn option group was created
option_group.updatedAn option group was updated
option_group.deletedAn option group was deleted
option.createdA product option was created
option.updatedA product option was updated
option.deletedA product option was deleted
bundle_rule.createdA bundle rule was created
bundle_rule.updatedA bundle rule was updated
bundle_rule.deletedA bundle rule was deleted
compatibility_rule.createdA compatibility rule was created
compatibility_rule.updatedA compatibility rule was updated
compatibility_rule.deletedA compatibility rule was deleted
Saved Configuration Events
saved_config.createdA product configuration was saved
saved_config.viewedA saved configuration was viewed
saved_config.convertedA saved configuration was converted to a deal
saved_config.expiringA saved configuration is about to expire
saved_config.expiredA saved configuration expired
Portal Events
portal.payment_completedA payment was completed via the customer portal
portal.contract_signedA contract was signed via the customer portal
portal.change_requestedA change was requested via the customer portal
Consent Events
consent.expiring_soonA customer consent record is about to expire
consent.expiredA customer consent record expired
Tenant & Trust Events
tenant.trust_level_changedA tenant's trust level changed
tenant.trust_promotedA tenant was promoted to a higher trust tier
tenant.trust_level_decay_warningA tenant's trust level is decaying
trust.demotedA trust entity was demoted to a lower tier
trust.fraud_signalA fraud signal was raised against a trust entity
Workflow Events
workflow.step_approvedA workflow step was approved
workflow.sell.proposal_receivedA sell workflow received a proposal
workflow.fulfill.deliveredA fulfillment workflow delivered its outcome
System & Infrastructure Events
job.completedA background job completed
job.failedA background job failed
queue.depth_alertA job queue depth exceeded its alert threshold
system.job_dead_letterA job was moved to the dead-letter queue
service.circuit_openedA circuit breaker opened due to repeated failures
service.circuit_closedA circuit breaker closed after recovery
circuit-breaker.backoff-increasedA circuit breaker increased its backoff interval
encryption.rekey_completedAn encryption re-key operation completed
security.csp_spikeA spike in CSP violation reports was detected
Other Events
payment.receivedA payment was received
credential.issuedA verifiable credential was issued
api_key.rotatedAn API key was rotated

Webhook Payload Format

All webhook payloads follow the same structure. Each delivery includes X-Salesbooth-Signature, X-Salesbooth-Timestamp, and X-Salesbooth-Delivery-Id headers.

Example Payload — deal.created
{ "event": "deal.created", "timestamp": "2026-03-09T10:30:00Z", "tenant_id": "tenant_abc123", "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
{ "event": "deal.status_changed", "timestamp": "2026-03-09T11:00:00Z", "tenant_id": "tenant_abc123", "data": { "id": "deal_abc123", "previous_status": "draft", "new_status": "in_progress", "changed_at": "2026-03-09T11:00:00Z" } }
Example Payload — deal.payment_received
{ "event": "deal.payment_received", "timestamp": "2026-03-09T12:00:00Z", "tenant_id": "tenant_abc123", "data": { "deal_id": "deal_abc123", "amount": "1099.00", "currency": "USD", "payment_intent_id": "pi_xxxxx", "status": "succeeded" } }
Example Payload — customer.created
{ "event": "customer.created", "timestamp": "2026-03-09T10:00:00Z", "tenant_id": "tenant_abc123", "data": { "id": "cust_xxxxx", "company": "Acme Corp", "status": "active", "created_at": "2026-03-09T10:00:00Z" } }
Example Payload — contract.signed
{ "event": "contract.signed", "timestamp": "2026-03-09T13:00:00Z", "tenant_id": "tenant_abc123", "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
{ "event": "negotiation.proposed", "timestamp": "2026-03-09T14:00:00Z", "tenant_id": "tenant_abc123", "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
{ "event": "negotiation.countered", "timestamp": "2026-03-09T15:00:00Z", "tenant_id": "tenant_abc123", "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
{ "event": "negotiation.accepted", "timestamp": "2026-03-09T16:00:00Z", "tenant_id": "tenant_abc123", "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
{ "event": "subscription.created", "timestamp": "2026-03-09T17:00:00Z", "tenant_id": "tenant_abc123", "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
{ "event": "subscription.past_due", "timestamp": "2026-04-09T17:05:00Z", "tenant_id": "tenant_abc123", "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
{ "event": "escrow.created", "timestamp": "2026-03-10T10:00:00Z", "tenant_id": "tenant_abc123", "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
{ "event": "subscription.renewed", "timestamp": "2026-04-09T17:00:00Z", "tenant_id": "tenant_abc123", "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
{ "event": "subscription.cancelled", "timestamp": "2026-03-12T10:00:00Z", "tenant_id": "tenant_abc123", "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 an X-Salesbooth-Signature header (v1= + HMAC-SHA256 of timestamp + "." + raw body) and an X-Salesbooth-Timestamp header (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) const signatureBuf = Buffer.from(signature); const expectedBuf = Buffer.from(expected); if (signatureBuf.length !== expectedBuf.length || !crypto.timingSafeEqual(signatureBuf, expectedBuf)) { 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.

GET /api/v1/audit?entity_type={type}&entity_id={id}
Retrieve the audit trail for an entity.
ParameterDescription
entity_type requireddeal, contract, customer, product
entity_id requiredThe entity identifier
limitMax results, 1–100 (default: 50)
offsetPagination offset
GET /api/v1/audit?entity_type={type}&entity_id={id}&action=verify
Verify the cryptographic hash chain integrity of an audit trail. Returns whether all entries are intact and untampered.
GET /api/v1/audit/export
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 text/csv download.
ParameterTypeDescription
entity_typestringdeal, contract, customer, or product
entity_idstringSpecific entity ID (required with entity_type for single-entity export)
start_datestringStart of date range (Y-m-d or Y-m-d H:i:s)
end_datestringEnd of date range (Y-m-d or Y-m-d H:i:s)
formatstringjson (default) or csv
limitintegerMax entries to return, 1–10000 (default: 1000)
offsetintegerPagination 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, "success": true, "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 five configurable factors: time_in_status, deal_value, line_items, discount, and customer_history. Default weights are 20 points each, all five factors are required, and weights must be non-negative integers that sum to exactly 100. You can override them per tenant via PATCH ?type=config.

GET /api/v1/intelligence?type=score&deal_id={deal_id}
AI-generated deal score (0–100) with factor breakdown, win probability, recommendation, and explanation.
ParameterTypeDescription
deal_id requiredstringThe 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, "success": true, "data": { "deal_id": "deal_abc123", "score": 74, "factors": { "time_in_status": { "score": 18, "max": 20, "detail": "Deal has been in status for 48 hours, within the configured 72-hour target", "points": 18, "max_points": 20 }, "deal_value": { "score": 16, "max": 20, "detail": "Deal value is close to the configured ideal value of $5,000.00", "points": 16, "max_points": 20 }, "line_items": { "score": 14, "max": 20, "detail": "Deal includes 3 line items, which is slightly above the tenant average", "points": 14, "max_points": 20 }, "discount": { "score": 12, "max": 20, "detail": "Discounting is within the normal range for similar won deals", "points": 12, "max_points": 20 }, "customer_history": { "score": 14, "max": 20, "detail": "Customer has a positive close history with this tenant", "points": 14, "max_points": 20 } }, "win_probability": 0.68, "recommendation": "Follow up while the deal is still within the ideal status window and avoid adding extra discounting unless the buyer pushes on price.", "explanation": "Strong overall signal driven by healthy time in status, solid customer history, and a deal value close to your target." } }
GET /api/v1/intelligence?type=pricing_suggestion&deal_id={deal_id}
AI-suggested optimal price for a deal based on comparable historical deals, customer segment, and pipeline data.
Response
{ "error": false, "success": true, "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 } }
GET /api/v1/intelligence?type=risk&deal_id={deal_id}
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, "success": true, "data": { "deal_id": "deal_abc123", "risk_level": "medium", "risk_score": 42, "risk_factors": [ { "type": "stall_risk", "severity": "high", "severity_score": 20, "detail": "Deal has been open 18.0 days (2.6x the average of 7.0 days for closed deals)", "action": "Follow up immediately — deal has been in \"in_progress\" for 18 days, which is 2.6x longer than average" }, { "type": "price_risk", "severity": "low", "severity_score": 10, "detail": "Deal value ($12,000.00) is 18% above the average closed deal ($10,200.00) — 1.7 standard deviations", "action": "Consider adjusting pricing or offering a discount — deal value is significantly above typical" } ], "recommended_actions": [ "Follow up immediately — deal has been in \"in_progress\" for 18 days, which is 2.6x longer than average", "Consider adjusting pricing or offering a discount — deal value is significantly above typical" ] } }
GET /api/v1/intelligence?type=close_forecast&deal_id={deal_id}
Predicted close date range for a specific deal based on pipeline velocity and historical patterns.
Response
{ "error": false, "success": true, "data": { "deal_id": "deal_abc123", "optimistic": "2026-03-28", "expected": "2026-04-08", "pessimistic": "2026-04-22", "confidence": 0.68, "factors": [ { "stage": "in_progress", "avg_days": 14.2, "sample_size": 184 }, { "factor": "deal_characteristics", "adjustment": 1.12, "detail": "Deal characteristics suggest slower than average close" } ] } }
GET /api/v1/intelligence?type=pipeline_forecast
Aggregate revenue forecast for all active pipeline deals. Sums probability-weighted close amounts by period.
ParameterTypeDescription
periodstring30, 60, 90, or all (default: all)
Response
{ "error": false, "success": true, "data": { "tenant_id": "tenant_abc123", "windows": { "30": { "days": 30, "weighted_value": 48250.00, "deal_count": 9, "at_risk_value": 12000.00 }, "60": { "days": 60, "weighted_value": 96400.00, "deal_count": 17, "at_risk_value": 22600.00 }, "90": { "days": 90, "weighted_value": 142750.00, "deal_count": 23, "at_risk_value": 31850.00 } }, "total_weighted_pipeline": 142750.00, "total_at_risk_value": 31850.00, "active_deals": 23, "closed_deals_analyzed": 48, "deals": [ { "deal_id": "deal_abc123", "title": "Enterprise renewal", "status": "in_progress", "value": 45000.00, "weighted_value": 27000.00, "at_risk": true, "expected_close_window": "60" } ], "trend": { "current_period_weighted": 142750.00, "previous_period_weighted": 131400.00, "pct_change": 8.64 }, "generated_at": "2026-03-12 10:00:00" } }
GET /api/v1/intelligence?type=win_probability_curve
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, "success": true, "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 } }
GET /api/v1/intelligence?type=score_history&deal_id={deal_id}
Historical scoring snapshots for a deal. Useful for charting score trends and correlating score changes with deal events.
ParameterTypeDescription
deal_id requiredstringThe deal to fetch history for
limitintegerMax snapshots (default: 20)
Response
{ "error": false, "success": true, "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" } ] } }
GET /api/v1/intelligence?type=score_accuracy
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, "success": true, "data": { "overall_accuracy": 79.0, "total_deals_analyzed": 356, "calibration": [ { "score_range": "61-80", "total_deals": 89, "won": 61, "lost": 28, "win_rate": 68.5, "avg_value": 12480.55 } ], "interpretation": "Deal scores predict outcomes with 79% accuracy — scoring model is well-calibrated.", "weight_suggestions": { "current_accuracy": 79.0, "suggestions": [], "summary": "Scoring model is well-calibrated at 79% accuracy. No weight adjustments needed." } } }
GET /api/v1/intelligence?type=pricing
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"
GET /api/v1/intelligence?type=pipeline
Pipeline analytics — deals by stage, conversion rates, average time-in-stage, and velocity metrics.
GET /api/v1/intelligence?type=outcome_analytics
Deal outcome analytics — win/loss rates, average deal size by outcome, revenue attributed, and time-to-close by segment.
GET /api/v1/intelligence?type=loss_patterns
Common patterns in lost deals. Clusters similar loss reasons to identify systemic issues (e.g. price too high, slow response, competitor).
GET /api/v1/intelligence?type=config
Get the current scoring configuration (weights, thresholds, enabled factors).
PATCH /api/v1/intelligence?type=config
Update deal scoring weights and thresholds. Requires intelligence:write scope. Weights must include all five factors as non-negative integers that sum to 100.
FieldTypeDescription
weightsobjectRequired keys: time_in_status, deal_value, line_items, discount, and customer_history. Values must be non-negative integers that sum to 100.
thresholdsobjectOptional factor-specific thresholds. Supported fields: time_in_status.ideal_hours and deal_value.ideal_value.
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": { "time_in_status": 30, "deal_value": 25, "line_items": 15, "discount": 10, "customer_history": 20 }, "thresholds": { "time_in_status": { "ideal_hours": 72 }, "deal_value": { "ideal_value": 5000 } } }'
POST /api/v1/intelligence?type=backtest
Backtest proposed scoring weights against your historical deal data before applying them. Returns accuracy comparison between proposed and current configuration.
FieldTypeDescription
weights requiredobjectProposed weight configuration to test. Include all five factor keys and make the integer values sum to 100.
thresholdsobjectOptional threshold overrides to test alongside the proposed weights.
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": { "time_in_status": 30, "deal_value": 25, "line_items": 15, "discount": 10, "customer_history": 20 }, "thresholds": { "time_in_status": { "ideal_hours": 72 }, "deal_value": { "ideal_value": 5000 } } }'
Response
{ "error": false, "success": true, "data": { "proposed_accuracy": 0.83, "current_accuracy": 0.79, "improvement": 0.04, "deals_tested": 356, "top_gains": [ { "stage": "pending_signature", "accuracy_delta": 0.09 } ] } }
GET /api/v1/intelligence?type=pipeline_deals&stage={stage}
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.
ParameterTypeDescription
stage requiredstringPipeline 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, "success": true, "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 } ] } }
GET /api/v1/intelligence?type=pricing_suggestions_bulk
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, "success": true, "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" } ] } }
GET /api/v1/intelligence?type=suggestion_analytics
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.
ParameterTypeDescription
daysintegerLookback 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, "success": true, "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 } } }
GET /api/v1/intelligence?type=counter_terms&deal_id={deal_id}
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.
ParameterTypeDescription
deal_id requiredstringThe deal to generate counter-terms for
current_termsstringJSON-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={"payment_terms":"net60","custom_terms":{"proposed_total":2125,"original_total":2500}}'
Response
{ "error": false, "success": true, "data": { "suggestions": [ { "type": "split_difference", "recommended_terms": { "payment_terms": "net30", "custom_terms": { "proposed_total": 2312.5, "original_total": 2500 } }, "confidence": 82, "win_probability_delta": 0.14, "rationale": "Countering at the midpoint preserves margin while improving close probability versus the buyer's net60 ask.", "risk_level": "low", "risk_assessment": "Low concession risk because the counter moves toward the buyer while keeping terms inside historical close ranges.", "acceptance_rate": 0.673 }, { "type": "counter_offer", "recommended_terms": { "payment_terms": "net30", "custom_terms": { "proposed_total": 2375, "original_total": 2500 } }, "confidence": 61, "win_probability_delta": 0.08, "rationale": "A lighter concession protects revenue and still aligns with accepted outcomes from similar deals.", "risk_level": "medium", "risk_assessment": "Moderate rejection risk if the buyer is anchored to a deeper discount or longer payment window.", "acceptance_rate": 0.412 } ], "deal_id": "deal_abc123", "suggestion_id": "sugg_abc123", "data_quality": "high", "historical_deals": 52, "currency": "USD", "reference_price": 2500, "current_proposed_price": 2125 } }

SDK Example — Score a Deal

const { SalesBooth } = require('@salesbooth/node'); const sb = new SalesBooth({ apiKey: 'sb_test_example_key_do_not_use' }); async function main() { // Score a deal and inspect the returned factors const result = await sb.intelligence.scoreDeal('deal_abc123'); console.log('Score:', result.score); // 74 console.log('Win probability:', result.win_probability); // 0.68 console.log('Recommendation:', result.recommendation); console.log('Explanation:', result.explanation); Object.entries(result.factors).forEach(([name, factor]) => { console.log(`${name}: ${factor.points}/${factor.max_points} - ${factor.detail}`); }); // 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.risk_level === 'high') { console.warn('High-risk deal:', risk.risk_factors.map(f => f.type)); } } main().catch((error) => { console.error(error); process.exitCode = 1; });

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.

GET /api/v1/activity
List activity feed events with optional filters.
ParameterTypeDescription
event_typestringFilter by event type (e.g. deal.created, payment.received)
actor_typestringFilter by actor: user, agent, or system
entity_typestringFilter by entity: deal, contract, customer
limitintegerMax results (default: 50, max: 100)
offsetintegerPagination 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"
GET /api/v1/activity?action=notifications
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"
GET /api/v1/activity?action=rules
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"
POST /api/v1/activity?action=create_rule
Create a notification rule.
FieldTypeDescription
event_type requiredstringEvent pattern to match (e.g. deal.signature_added, payment.*)
channelsarrayDelivery channels array. Allowed values: in_app, email, sms, and webhook. Defaults to ["in_app"] when omitted. If channels includes webhook, provide webhook_url.
namestringRule display name
webhook_urlstringWebhook destination URL. Required when channels includes webhook.
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", "channels": ["email"], "name": "Notify on deal sign" }'
POST /api/v1/activity?action=mark_read
Mark specific notifications as read. Use action=mark_all_read to mark all as read at once.
FieldTypeDescription
notification_ids requiredarrayArray 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"] }'
POST /api/v1/activity?action=test_notification
Send a test in-app notification to verify your Activity Feed notification configuration. No request body fields are required.

No request body fields are required. Omit the body or send an empty JSON object.

Example
curl -X POST "https://api.salesbooth.com/v1/activity?action=test_notification" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{}'
PATCH /api/v1/activity?action=update_rule&rule_id={rule_id}
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 '{ "channels": ["webhook"], "webhook_url": "https://example.com/activity-webhook" }'
DELETE /api/v1/activity?action=delete_rule&rule_id={rule_id}
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"
GET /api/v1/activity?action=preferences
Retrieve the tenant’s activity notification preferences. Returns category, threshold, and quiet-hours schedule preferences.
Example
curl "https://api.salesbooth.com/v1/activity?action=preferences" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{ "error": false, "success": true, "data": { "categories": { "deals": { "in_app": true, "email_enabled": true, "email_digest": "immediate", "enabled": true } }, "thresholds": {}, "schedule": {} } }
PUT /api/v1/activity?action=preferences
Save the tenant’s activity notification preferences. Replaces all notification preferences for the authenticated tenant. Send the full preferences object using category, threshold, and quiet-hours schedule settings.
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 '{ "categories": { "deals": { "in_app": true, "email_enabled": true, "email_digest": "immediate", "enabled": true } }, "thresholds": {}, "schedule": {} }'

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 operations in a batch run inside one transaction. Any failure rolls back all mutations and returns a structured error with the failed operation and the number of operations completed before rollback. The results array is returned only when every operation succeeds.

POST /api/v1/batch
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.
FieldTypeDescription
operations requiredarrayArray 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", "email": "buyer@example.com" } }, { "method": "POST", "resource": "deals", "body": { "title": "Enterprise Plan" } }, { "method": "PATCH", "resource": "deals", "id": "deal_existing", "body": { "description": "Expanded rollout scope" }, "version": 3 }, { "method": "PATCH", "resource": "deals", "id": "deal_existing", "action": "transition", "body": { "status": "in_progress" }, "version": 3 } ] }'

Note: Deal status changes in batch requests must use PATCH with a top-level action of transition and the target status inside body.

Response
{ "error": false, "success": true, "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" } }, { "index": 3, "status": 200, "data": { "id": "deal_existing", "status": "in_progress" } } ], "total": 4 } }

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.

Dashboard-managed builder. AI Sales Agent creation, approval, lifecycle, and knowledge-management actions are part of the Salesbooth admin experience and are not published as public external API endpoints.

Public integration path. Use the agent registry, tools, MCP, deal, contract, payment, widget, and webhook APIs to connect your own agents to Salesbooth's governed commerce workflows.

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.

GET /api/v1/tools
List agent tool definitions. Supports OpenAI, Anthropic, and universal formats.
ParameterDescription
formatuniversal (default), openai, or anthropic
categoryFilter: 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: AI provider Function-Calling
curl https://api.salesbooth.com/v1/tools?format=openai \ -H "Authorization: Bearer sb_test_example_key_do_not_use"

Available Tools

ToolCategoryDescription
discover_deals deal_management 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.
get_deal_terms_schema deal_management Retrieve the JSON Schema for structured deal terms. Use this to understand the valid structure for deal_terms when creating deals or making proposals.
create_deal deal_management Create a new deal for a customer. Defaults to "draft" status but can be created directly as "in_progress". Add line items with add_deal_item, then transition to "in_progress" when ready. To set deal terms after creation, use the set_deal_terms tool.
check_deal_status deal_management Get the current state of a deal including status, line items, total amount, and signatures. Use this to verify deal state before taking action.
update_deal deal_management Update deal fields. Use transition_deal for status changes. Requires the current version from a prior GET for optimistic concurrency.
search_deals deal_management Search deals by status, customer, or date range. Returns matching deals with pagination. Use to find existing deals or check for duplicates.
add_deal_item deal_management Add a line item (product) to an existing deal. The deal must be in draft or in_progress status.
remove_deal_item deal_management Remove a line item from a deal. The deal must be in draft or in_progress status.
apply_deal_discount deal_management Apply a discount to a deal. Supports fixed amount or percentage discounts.
transition_deal deal_management Transition a deal to a new status. Use get_valid_transitions to check allowed transitions for a given deal.
cancel_deal deal_management Cancel a deal. Records the cancellation reason. This action cannot be undone.
accept_deal deal_management Accept and close a deal. Transitions to "closed" status. This action is irreversible.
partial_accept_deal deal_management Partially accept a deal by specifying which line items to keep (accepted_items) and which to reject (rejected_items). Rejected items are removed and totals are recalculated. The deal transitions to "partially_accepted" status and a deal.partially_accepted webhook fires. Optionally, rejected items can be saved to a new declined deal for record-keeping. Use this when a buyer wants some items from a quote but not others.
sign_deal closure Sign a deal on behalf of the authenticated principal. The deal must be in pending_signature status. Requires deals:sign scope. The signature method is derived server-side from the auth type (session_auth, delegation_auth, or api_key_auth). Use verify_deal_signature afterward to confirm integrity.
verify_deal deal_management Verify the integrity of a deal audit chain.
get_valid_transitions deal_management Get valid status transitions for a deal based on its current state and business rules.
set_deal_terms deal_management Set structured terms on a deal (payment terms, delivery, warranty, etc.). Use get_deal_terms_schema first to understand the valid schema.
record_deal_outcome deal_management Record the outcome of a closed or cancelled deal (win/loss reason, competitor, notes).
create_configured_deal deal_management Create a complete, configured deal in a single atomic call. Validates products, configurations, creates/finds customer by email, adds all line items with configurations, applies discounts, and optionally merges template defaults. All-or-nothing: if any validation fails, nothing is created. Use dry_run=true to validate without creating. Provide either items (explicit line items) or saved_config_id (load items from a saved configuration) — at least one is required.
list_products product_catalog Browse available products. Returns product details including pricing, configuration options, and compatibility rules.
get_product product_catalog Get a single product by ID with full details including pricing tiers and configuration options.
create_product product_catalog Create a new product in the catalog with pricing and configuration options.
update_product product_catalog Update an existing product. Partial updates supported.
delete_product product_catalog Delete (archive) a product from the catalog.
configure_product product_catalog Validate a product configuration against its rules. Returns whether the configuration is valid and any compatibility issues. Use before adding to a deal.
calculate_pricing product_catalog Calculate pricing for a product configuration. Returns total price, discounts, and breakdown.
get_configuration_options product_catalog Get a product's configuration schema in a structured format agents can reason about. Returns option groups, available values, price modifiers, and constraints. Use this before calling create_configured_deal to understand what configuration keys and option IDs are valid for each product.
list_customers customer_management List or search customers. Supports filtering by status and keyword search across name, email, phone, and company.
get_customer customer_management Get a single customer by ID with full details including deals and activity log.
create_customer customer_management Create a new customer. Name and email are required. PII is encrypted at rest.
update_customer customer_management Update a customer record. Partial updates supported. Requires the current version from a prior GET for optimistic locking.
delete_customer customer_management Delete a customer. Requires If-Match header. For GDPR erasure, use gdpr_erase_customer_data instead.
list_contracts contracts List contracts with optional filtering by status, customer, renewal type, or expiration.
get_contract contracts Get a single contract by ID with full details.
create_contract contracts Create a new contract. Supply deal_id to auto-populate customer, title, value, currency, and dates from a deal (fields can still be overridden). Without deal_id, customer_id, title, value, start_date, and end_date are required.
update_contract contracts Update contract fields. Partial updates supported. Requires the current version from a prior GET for optimistic locking.
sign_contract contracts Digitally sign a contract using Ed25519. The contract should be in draft or pending status.
activate_contract contracts Activate a signed or pending contract, making it effective.
terminate_contract contracts Terminate an active contract.
delete_contract contracts Use this tool to delete a contract. The contract must not be active — terminate it first. Returns confirmation of deletion.
create_contract_from_deal contracts Use this tool to create a contract directly from a closed deal. Copies deal terms, line items, and customer into the contract. Requires a closed deal ID.
renew_contract contracts Manually trigger renewal of a contract, creating a successor contract with updated dates and optional price adjustment. Works on any active contract regardless of renewal_type. The original contract is expired and a new contract linked via parent_contract_id is created.
negotiate_terms negotiation Propose, counter-propose, accept, or reject deal terms. Creates a negotiation round. The deal must be in "in_progress" status. Note: the "accept" action requires agent:execute scope; propose/counter/reject require only agent:negotiate.
get_negotiation_history negotiation View negotiation history for a deal. Returns all rounds of proposals, counter-proposals, and outcomes.
get_negotiation_intelligence negotiation Use this tool to get pricing intelligence for a deal negotiation. Returns recommended pricing, market comparisons, and negotiation guidance. Requires deal_id.
suggest_counter_terms negotiation Get AI-powered counter-proposal recommendations for an active negotiation. Returns confidence-scored suggestions based on historical deal data. Use this when the other party has countered and you need data-driven guidance on what to propose next. Different from get_negotiation_intelligence (pre-negotiation pricing) — this is mid-negotiation counter-term advice.
list_templates templates List available deal templates. Templates provide reusable deal structures.
get_template templates Get a single deal template by ID with full configuration.
create_template templates Create a new deal template for reuse.
instantiate_template templates Create a new deal from a template. Copies the template structure and applies any overrides.
clone_template templates Clone an existing template to create a modified copy.
update_template templates Use this tool to update an existing deal template. Supports partial updates to name, description, terms, and line items.
delete_template templates Use this tool to soft-delete a deal template. The template will be deactivated but retained for historical reference.
score_deal intelligence Get an AI-powered score for a deal based on deal attributes, customer history, and market signals.
get_pricing_intelligence intelligence Get pricing analytics and recommendations based on historical deal data.
get_pipeline_intelligence intelligence Get deal pipeline analytics including conversion rates, average deal size, and velocity.
get_outcome_analytics intelligence Get deal outcome analytics — win/loss rates, patterns, and trends.
get_intelligence_config intelligence Get the current intelligence scoring configuration (weights and thresholds).
update_intelligence_config intelligence Update intelligence scoring weights and thresholds.
get_pricing_suggestion intelligence Use this tool to get an AI-powered pricing suggestion for a specific deal. Returns recommended price adjustments based on deal attributes and market data.
get_score_accuracy intelligence Use this tool to get scoring model accuracy metrics. Returns calibration data and weight adjustment suggestions.
get_loss_patterns intelligence Use this tool to analyze loss patterns across deals. Returns common reasons for deal failure and actionable insights.
backtest_intelligence intelligence Use this tool to backtest proposed scoring weights against historical deal data. Returns predicted accuracy before applying changes.
get_score_history intelligence Get the score evolution history for a deal over time. Returns timestamped score entries showing how the deal score changed as attributes and market data evolved. Use this to track deal momentum and identify inflection points.
get_suggestion_analytics intelligence Get analytics on counter-proposal suggestion acceptance rates. Returns metrics on how often AI-generated counter-term suggestions were accepted, rejected, or modified, helping calibrate the suggestion engine.
get_pipeline_deals intelligence Get deals grouped by a specific pipeline stage, each enriched with their latest AI score and win probability. Use this to identify which deals in a given stage need attention or are ready to advance.
get_bulk_pricing_suggestions intelligence Get bulk discount opportunity suggestions across all open deals. Returns deals where a targeted discount is likely to increase win probability based on product-level historical close data. Use this for batch deal optimization.
get_win_probability_curve intelligence Get the logistic regression win probability calibration curve. Returns the relationship between deal scores and actual win rates, used to calibrate win_probability values. Useful for understanding model reliability.
get_payment_status payments Get payment status and history for a deal.
create_payment_intent payments Create a Stripe PaymentIntent for a deal. Returns a client_secret for frontend payment completion.
confirm_payment payments Confirm a completed payment and transition the deal accordingly.
refund_payment payments Refund a payment. Supports full or partial refunds.
record_manual_payment payments Record a manual (offline) payment such as cash, wire, or cheque.
charge_saved_payment_method payments Charge a customer's saved payment method server-side without requiring frontend UI. Creates and immediately confirms a Stripe PaymentIntent off-session. The customer must have previously saved a card (via widget with setup_future_usage=off_session). Validates delegation spending limits before charging. On success, transitions deal from pending_payment → closed.
poll_payment_status payments Check the current Stripe PaymentIntent status directly without relying on webhooks. Returns status, amount_received, and any payment error. Use in workflows to monitor payment completion after create_payment_intent or generate_payment_link.
generate_payment_link payments Generate a Stripe Checkout Session URL that can be sent to the customer (via email or notification). The agent does not need browser/UI access — it creates a hosted payment page the customer clicks to complete payment. When the customer pays, a payment.received webhook fires and the deal transitions to closed. Also sets setup_future_usage=off_session so the card is saved for future charge_saved_payment_method calls.
list_subscriptions subscriptions List subscriptions with optional status filter. Returns recurring deal billing information.
create_subscription subscriptions Create a recurring subscription for a deal. Sets up billing cycle and renewal.
pause_subscription subscriptions Pause an active subscription. Billing is suspended until resumed.
resume_subscription subscriptions Resume a paused subscription.
cancel_subscription subscriptions Cancel a subscription. Can cancel immediately or at end of current billing period.
get_subscription subscriptions Use this tool to get subscription details for a specific deal including renewal history and billing cycle information.
renew_subscription subscriptions Use this tool to manually trigger renewal of a subscription, creating a new deal for the next billing period.
change_subscription subscriptions Use this tool to upgrade or downgrade a subscription by changing its line items. Proration is applied automatically.
change_subscription_cycle subscriptions Use this tool to switch a subscription billing cycle (e.g. monthly to annual). Proration is calculated automatically.
retry_subscription_payment subscriptions Use this tool to retry payment for a past-due subscription. Optionally extends grace period.
subscription_analytics subscriptions Use this tool to get subscription analytics including MRR, ARR, churn rate, and retention metrics.
list_widgets widgets List all configured deal widgets.
create_widget widgets Create a new embeddable deal widget with product configuration and styling.
update_widget widgets Update a widget configuration. Partial updates supported.
delete_widget widgets Delete a widget configuration and revoke its publishable key.
auto_configure_widget widgets Auto-generate a widget configuration from product IDs. Analyzes products and suggests optimal layout.
list_product_families configuration List product families. Families group related products with shared configuration.
create_product_family configuration Create a product family for grouping related products.
list_option_groups configuration List option groups. Option groups define configurable choices for products.
create_option_group configuration Create an option group with configurable selection rules.
get_product_rules configuration Get all compatibility and bundle rules for a product.
validate_product_rules configuration Validate selected options against a product's compatibility and bundle rules.
simulate_bundle_pricing configuration Calculate total pricing for a multi-product cart including bundle discounts, compatibility rules, and volume pricing. Returns subtotal, bundle discount breakdown, and total. Does NOT create a deal — pure simulation. Use this to preview savings before committing to checkout.
compare_cart_scenarios configuration Compare 2-4 cart configurations side-by-side. Returns a pricing breakdown for each scenario ranked by total cost. Use this to find the optimal product combination before committing to a deal.
analyze_negotiation_history intelligence Analyze historical negotiation patterns for a product or category. Returns average discount granted, typical round count, success rate by discount tier, and an optimal opening offer suggestion. Use this to calibrate negotiation strategy before proposing terms.
save_configuration saved_configs Save a product configuration for sharing via short code. Returns a shareable link.
load_saved_config saved_configs Load a saved configuration by its short code.
convert_config_to_deal saved_configs Convert a saved configuration into a deal, creating customer and line items from the stored snapshot.
convert_saved_config saved_configs Atomically convert a saved configuration into a deal. Loads the saved config, creates/finds the customer, creates the deal with all line items and option selections, applies optional discounts, and marks the config as converted. Prevents double-conversion. Reports price changes between snapshot and current prices. Validates delegation spending limits.
delete_saved_config saved_configs Delete a saved configuration by its short code.
list_webhooks webhooks List registered webhook endpoints with delivery status.
create_webhook webhooks Register a new webhook endpoint to receive event notifications.
delete_webhook webhooks Delete a webhook endpoint.
test_webhook webhooks Send a test event to a webhook endpoint to verify connectivity.
rotate_webhook_secret webhooks Rotate the signing secret for a webhook endpoint.
get_webhook webhooks Use this tool to get details of a single webhook endpoint including events, status, and delivery stats.
update_webhook webhooks Use this tool to update a webhook endpoint configuration (URL, events, description, status).
list_webhook_deliveries webhooks Use this tool to list delivery history for a webhook endpoint. Shows status, response codes, and timestamps.
list_delegations delegations List agent delegations with optional status filter.
create_delegation delegations Create a delegation granting another agent specific permissions with spending limits.
revoke_delegation delegations Revoke an active delegation, immediately removing the grantee's permissions.
verify_delegation delegations Verify whether a delegation is valid and what permissions it grants.
get_delegation delegations Use this tool to get details of a specific delegation including scope, spending limits, and expiry.
update_delegation delegations Use this tool to update delegation spending limits, allowed actions, or expiry.
delegation_propose delegations Propose a delegation to another agent. Agent A uses this to hire Agent B as a sub-agent with specific permissions and spending limits. Requires trust level 2+ and the "delegate" action in your own delegation scope. The target agent will see this proposal and can accept, reject, or counter it.
delegation_list_pending delegations List pending delegation proposals targeting this agent. Use this to see if any other agents want to hire you as a sub-agent.
delegation_accept delegations Accept a pending delegation proposal. This creates an actual delegation granting you the proposed permissions from the proposing agent. Use delegation_list_pending first to see available proposals.
delegation_reject delegations Reject a pending delegation proposal with an optional reason.
delegation_counter delegations Counter-propose modified terms for a pending delegation. You can propose a subset of the original actions and/or lower spending limits. Cannot exceed the original proposal's scope.
export_audit_trail compliance Export audit trail as a compliance evidence package. Supports single entity, date range, or bulk export.
gdpr_export_customer_data compliance Export all data held about a customer (GDPR Article 20 data portability).
gdpr_erase_customer_data compliance Erase all customer data (GDPR Article 17 right to erasure). This action is irreversible.
gdpr_record_consent compliance Record customer consent for a specific data processing purpose.
global_search search Use this tool to search across all entity types (customers, products, deals, contracts). Returns ranked results with type and relevance. Requires a query of at least 2 characters.
list_audit_events audit Use this tool to list audit trail events for a specific entity. Returns chronological event history with actor, action, and timestamp. The required scope depends on entity_type: deals:read for deals, contracts:read for contracts, customers:read for customers, products:read for products.
verify_audit_chain audit Use this tool to verify the integrity of the audit hash chain for an entity. Returns whether the chain is intact and unmodified. The required scope depends on entity_type: deals:read for deals, contracts:read for contracts, customers:read for customers, products:read for products.
sandbox_reset sandbox Reset the sandbox environment. Deletes all test data. Requires a test API key (sb_test_*).
sandbox_seed sandbox Seed the sandbox with sample test data (customers, products, deals, contracts).
sandbox_status sandbox Get sandbox environment status and record counts.
sandbox_simulate_webhook sandbox Simulate a webhook event in sandbox for testing integrations.
workflow_plan workflows Plan an autonomous deal workflow. Validates delegation scope, discovers products within budget, and builds a step-based execution plan. Supports customer lookup by ID or email.
workflow_execute workflows Execute a planned workflow asynchronously. Returns immediately with workflow_id and enqueues steps as background jobs. Poll status to track progress.
workflow_modify workflows Modify an in-progress workflow's deal. Apply discounts, update metadata, or add notes between steps. Workflow must be executing and have a deal created.
workflow_get workflows Get a workflow by ID. Returns status, current step, completed steps, next step, and result.
workflow_list workflows List workflows for the current tenant. Supports status and delegation_id filtering for concurrent workflow tracking.
workflow_cancel workflows Cancel a planned or executing workflow. Cleans up any created deal. Cannot cancel completed or failed workflows.
workflow_list_pending_approvals workflows List all workflows currently awaiting human approval, sorted oldest-first (most urgent). Returns time_waiting and token expiry status for each. Use this instead of polling workflow_list to check the approval queue.
workflow_check_approval_status workflows Check the detailed approval token status for a specific workflow. Returns token_status (pending/expired/approved/rejected), time remaining until expiry, and approver info if already actioned.
workflow_resend_approval workflows Resend the approval notification for a workflow stuck in awaiting_approval. Generates a new token (invalidating the old one) and re-dispatches the webhook with fresh deep-link URLs. Rate limited to 3 resends per workflow per 24 hours.
workflow_escalate_approval workflows Escalate a pending approval to the delegation grantor (parent authority) when the original approver is unresponsive. Generates a new token, dispatches a webhook to the grantor, and logs the escalation in the audit trail.
workflow_approve_step workflows Approve a workflow step that is awaiting approval, using delegation scope instead of an admin session. The approving agent must have a delegation that includes the "workflow:approve" action, trust level >= 2, and sufficient budget headroom. Emits a workflow.step_approved webhook with the full delegation chain. Error codes: insufficient_delegation_scope, trust_too_low, budget_exceeded, delegation_invalid.
workflow_reject_step workflows Reject a workflow step awaiting human approval, moving the workflow to cancelled state and releasing its budget reservation. Emits an agent.workflow.cancelled webhook with the rejection reason. Use this to deny workflows that violate policy, exceed risk thresholds, or should not proceed. Error codes: invalid_status (workflow not in awaiting_approval).
workflow_spending_summary workflows Retrieve workflow activity and execution statistics for all agents in this tenant, grouped by agent key. Use this for budget monitoring and to understand which agents are most active. Returns current-period stats alongside a previous-period comparison for trend analysis.
workflow_detect_anomalies workflows Detect anomalous workflow execution patterns for sub-agents in this tenant, including volume spikes, unusual deal values, and abnormal failure rates. Returns flagged agents with anomaly type, deviation score, and recommended action — enabling hierarchical agent oversight and self-governance.
workflow_agent_stats workflows Get detailed performance statistics for a specific agent key: total workflow counts, success/failure rates, deal volume, active delegations, and a historical trend broken down by day or week. Use this to audit a sub-agent's behaviour before adjusting its delegation limits.
get_agent_trust_status agent_trust Get the current agent trust level, score, unlocked capabilities, transaction cap, and progress toward the next level.
check_trust_lock agent_trust Check whether a specific capability is unlocked for the current agent. Returns allowed status and required trust level.
get_agent_trust_history agent_trust Get the history of trust level changes for the current agent.
export_trust_credential agent_trust Export the current agent's W3C Verifiable Credential for trust portability. The credential contains the agent's trust level, score, and deal history, signed by the tenant's Ed25519 key. Requires trust level 2+. Returns 404 if no credential has been issued yet — issue one via POST /api/v1/agent-trust-credentials?action=issue first.
verify_trust_credential agent_trust Verify or present a W3C Verifiable Credential for agent trust. Use action=verify to check a credential's signature and validity. Use action=present to bootstrap trust on this instance from a verified credential.
cross_instance_discover federation Discover available products and deals on a remote Salesbooth instance. Fetches the remote instance's discovery manifest and catalog summary. Use this to find offerings across the federation.
cross_instance_negotiate federation Send a signed negotiation envelope to a remote Salesbooth instance. Supports propose, counter, accept, and reject actions. Both agents' trust scores are verified before negotiation proceeds.
federation_escrow_coordinate federation Coordinate escrow creation between two Salesbooth instances. Creates matched escrow records on both sides with cross-reference IDs for audit trail federation.
federation_audit_trail federation Get the federated audit trail for a cross-instance negotiation. Returns all events linked by a cross-reference ID, enabling full traceability across instances.
federation_escrow_settle federation Settle a coordinated cross-instance escrow using 2-phase commit (PREPARE → COMMIT/ROLLBACK). Both instances release escrow atomically, or neither does. If the remote instance rejects the prepare, the local escrow remains held and a settlement_failed event is fired.
federation_escrow_dispute federation Initiate a cross-instance escrow dispute. Freezes escrow on both instances, sends a signed dispute envelope to the remote side, and fires webhook events for both parties. The escrow remains frozen pending out-of-band resolution.
list_active_agents agent_registry List agents (delegations) currently active in the same tenant. Results respect delegation hierarchy — agents see peers and children, not ancestors. Use this before starting a workflow to check whether another agent is already working on the same task.
get_agent_activity agent_registry Get a specific agent's recent activity summary. Returns aggregate workflow counts by status, recent deals (last 10), and spending summary. Does not expose internal workflow details or negotiation positions.
check_product_contention agent_registry Check if other agents are already working on the same products. Returns active deals and workflows for each product ID, enabling agents to avoid duplicate negotiations or bidding against their own organization.
deal_add_participant deal_participants Invite another agent to collaborate on a deal with a specific role (subcontractor, reviewer, observer) and optional revenue share. Requires primary role on the deal or manage_participants delegation action.
deal_accept_participation deal_participants Accept an invitation to participate in a deal. Changes participant status from "invited" to "accepted".
deal_complete_scope deal_participants Mark your scope as complete on a deal. Subcontractor participants must complete before the deal can close. Changes status from "accepted"/"active" to "completed".
deal_list_participants deal_participants List all agents participating in a deal with their roles, scope, status, and revenue share assignments.
deal_get_settlements deal_participants View the revenue settlement breakdown for a closed deal. Shows each participant's share amount, currency, and payment status.
capture_payment closure Capture a previously-authorized Stripe PaymentIntent. Use for deposit/authorize flows where payment was set up but not captured immediately. Returns captured amount and updates deal payment status. Requires the deal to have an authorized payment_intent_id.
verify_deal_signature closure Verify a deal's cryptographic signature integrity. Returns verification status: "verified" (signature valid and hash matches), "tampered" (hash mismatch — deal was modified after signing), or "unsigned" (no signature recorded). Use before executing complete_deal to confirm the counterparty signature is valid.
atomically_close_deal closure Validate that ALL required participant signatures are present before closing a multi-party deal. Checks signature_count >= required_signatures, then transitions the deal to "closed" atomically. Returns a structured error with missing_signatures array (participant IDs + agent names) if any required signers have not yet signed. Use this instead of complete_deal when the deal has required_signer participants. Requires agent:execute scope.
complete_deal closure Atomically close a fully-signed and fully-paid deal. Guards: deal must have a valid signature (verified by verify_deal_signature) AND payment covering total or deposit. Transitions deal to "closed" status, emits deal.closed webhook, records delegation spend, and issues deal credentials. This is the final step of autonomous agent commerce. Requires agent:execute scope.
update_product_schema catalog_management Update a product's configuration_schema — the set of option groups and rules that govern how the product can be configured. Validates schema structure before saving. Use this to add, remove, or reorder option groups on a product. Requires products:write scope.
update_product_pricing catalog_management Update a product's price and pricing model. Validates pricing constraints (price must be > 0, pricing_model must be one of fixed, tiered, volume, or usage). Use this to implement dynamic pricing strategies or respond to market changes. Requires products:write scope.
create_bundle_rule catalog_management Create a bundle pricing rule that applies a fixed or percentage discount when specific option combinations are purchased together. Enforces FK constraints — all referenced option IDs must exist. Requires products:write scope.
update_bundle_rule catalog_management Update an existing bundle pricing rule. Supports partial updates — only supply fields to change. Requires products:write scope.
delete_bundle_rule catalog_management Delete a bundle pricing rule. This is a permanent deletion — the rule will no longer apply to any new configurations. Requires products:write scope.
create_compatibility_rule catalog_management Create a compatibility rule between two options. Rule types: "requires" (selecting source forces target), "excludes" (selecting source prevents target), "includes_price" (selecting source adds target's price). Validates that both option IDs exist. Requires products:write scope.
update_compatibility_rule catalog_management Update an existing compatibility rule. Supports partial updates. Use to change rule type, message, or enable/disable a rule without deleting it. Requires products:write scope.
delete_compatibility_rule catalog_management Delete a compatibility rule permanently. Once deleted, the constraint between the two options is removed. Requires products:write scope.
update_option_group catalog_management Update an existing option group's metadata, selection rules, or display style. Supports partial updates. Use this to rename groups, change selection constraints, or update the display style. Requires products:write scope.
delete_option_group catalog_management Archive (soft-delete) an option group. Archived groups are removed from new product configurations but historical data is preserved. Requires products:write scope.
generate_quote documents Generate a formal quote from a deal in any status. Returns structured quote data with line items, terms, total, validity period, and a shareable URL the customer can open without logging in. The quote captures the current deal state as a snapshot and automatically expires after the validity period.
generate_invoice documents Generate an invoice for a deal in closed, pending_payment, or in_progress status. Wraps InvoiceService and returns invoice data with a downloadable URL. If an invoice already exists for the deal, returns the existing one. For recurring deals, creates a subscription invoice.
send_deal_notification documents Send a notification to the deal's customer via their preferred channel (email or SMS). Wraps CustomerNotificationService with agent-specific notification types. Delivery is logged in the activity stream. Rate limited to 10 notifications per hour per API key. Use get_customer_contact_preferences first to verify the customer has contact info on file.
get_customer_contact_preferences documents Retrieve a customer's preferred contact channel, whether they have email and phone on file, marketing consent status, and their last 5 notifications. Use this before send_deal_notification to confirm the customer can be reached and to choose the right communication channel.
check_credit_balance billing Check the tenant's current credit balance, trust level, auto top-up configuration, and estimated remaining deal capacity. Call this before planning any multi-step workflow that deducts credits to pre-check affordability and avoid mid-execution failures.
headless_validate_configuration headless_flow Validate the current product configuration for a headless widget session. Checks that all required option groups are filled, compatibility rules are satisfied, and returns any price adjustments. Call before advancing the customer to the summary or payment step.
headless_preview_payment headless_flow Preview the payment amount for the current headless widget cart, including subtotal, tax, discounts, and deposit breakdown. Use this to show the customer what they will be charged before initiating payment.
headless_validate_promo_code headless_flow Validate a promotional code against the current headless widget cart. Accepts scoped API keys with widgets:read, publishable widget keys, or same-origin session auth. On invalid code the endpoint returns HTTP 422 with { error: true, code: "promo_error.*", message: "..." }. Respects the widget enablePromoCodes setting.

MCP Server

The /api/v1/mcp endpoint implements the Model Context Protocol over HTTP using JSON-RPC 2.0.

POST /api/v1/mcp
MCP JSON-RPC 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.
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/sdk/agent'); async function main() { const agent = SalesboothAgent.init({ apiKey: 'sb_test_example_key_do_not_use', delegationId: 'del_xxxxx' // optional }); // Get tool definitions for AI provider const tools = agent.getToolDefinitions('openai'); // Execute a tool const deals = await agent.executeTool('discover_deals', { category: 'software', max_price: 10000 }); } main().catch(console.error);
Via the agent SDK
const SalesboothAgent = require('@salesbooth/sdk/agent'); const agent = SalesboothAgent.init({ apiKey: 'sb_test_example_key_do_not_use', delegationId: 'del_xxxxx' }); const tools = agent.getToolDefinitions('anthropic');

Agent Scopes

ScopeDescription
agent:discoverDiscover deals, browse products, and read tool definitions
agent:negotiatePropose, counter, or reject deal terms
agent:executeAccept negotiated terms, 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.

GET /api/v1/agent-workflow
List agent workflows or retrieve a specific workflow with its execution history.
ParameterTypeDescription
actionstringQuery action: spending_summary, anomalies, agent_stats, pending_approvals, approval_status
idstringRetrieve a specific workflow
statusstringFilter: planned, executing, negotiating, awaiting_approval, completed, failed, cancelled, degraded, dead_letter
delegation_idstringFilter by delegation
limitintegerMax results (default: 50)
Example
curl https://api.salesbooth.com/v1/agent-workflow?status=executing \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
GET /api/v1/agent-workflow?action=spending_summary
Return agent spending analytics broken down by period.
ParameterTypeDescription
periodstringAggregation 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"
GET /api/v1/agent-workflow?action=anomalies
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"
GET /api/v1/agent-workflow?action=agent_stats
Return performance statistics for a specific agent key.
ParameterTypeDescription
agent_id requiredstringAgent key ID to retrieve statistics for
granularitystringTime 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"
GET /api/v1/agent-workflow?action=pending_approvals
List all workflows currently paused at an approval gate and awaiting a decision.
ParameterTypeDescription
delegation_idstringFilter by delegation
limitintegerMax results (default: 50, max: 100)
offsetintegerPagination 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"
GET /api/v1/agent-workflow?action=approval_status&id={workflow_id}
Check the approval token status for a specific workflow — whether the one-time approval link has been used.
ParameterTypeDescription
id requiredstringWorkflow 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"
POST /api/v1/agent-workflow
Plan a new workflow. The system generates a step-by-step execution plan based on the agent’s intent.
FieldTypeDescription
delegation_id requiredstringDelegation providing spending limits
intent requiredstringWorkflow intent enum: purchase, sell, or fulfill
constraintsobjectAdditional planning constraints such as max_budget and product_categories
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": "purchase", "constraints": { "max_budget": 5000, "product_categories": ["software"] } }'
POST /api/v1/agent-workflow?id={workflow_id}&action=execute
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"
POST /api/v1/agent-workflow?id={workflow_id}&action=modify
Modify a workflow’s associated deal while it is in progress.
FieldTypeDescription
(modifications) requiredobjectKey-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 }'
POST /api/v1/agent-workflow?id={workflow_id}&action=approve
Approve a workflow paused at an approval gate. Supports either an authenticated admin session or a one-time approval token passed in the query string or JSON body for webhook deep-links.
Field / ParameterTypeDescription
tokenstringOne-time approval token (query param or body field) for token-based approval without a session
approved_bystringIdentifier of the approving party (body)
notestringOptional approval note (body)
Example — token-only approval link
curl -X POST "https://api.salesbooth.com/v1/agent-workflow?id=wf_xxxxx&action=approve&token=apt_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "approved_by": "approver@example.com", "note": "Approved from email link" }'
Example — admin session / API key
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" }'
POST /api/v1/agent-workflow?id={workflow_id}&action=reject
Reject a workflow paused at an approval gate. Supports either an authenticated admin session or a one-time approval token passed in the query string or JSON body for webhook deep-links.
Field / ParameterTypeDescription
tokenstringOne-time approval token (query param or body field) for token-based rejection without a session
rejected_bystringIdentifier of the rejecting party (body)
reasonstringOptional rejection reason (body)
Example — token-only rejection link
curl -X POST "https://api.salesbooth.com/v1/agent-workflow?id=wf_xxxxx&action=reject&token=apt_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "rejected_by": "approver@example.com", "reason": "Budget needs manual review" }'
Example — admin session / API key
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" }'
POST /api/v1/agent-workflow?id={workflow_id}&action=resend_approval
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"
POST /api/v1/agent-workflow?id={workflow_id}&action=escalate_approval
Escalate a pending approval request to the delegation grantor when the original reviewer is unresponsive.
FieldTypeDescription
escalation_reason requiredstringReason 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" }'
POST /api/v1/agent-workflow?id={workflow_id}&action=delegate_approve
Approve a paused workflow using delegated authority — allows an agent key with the appropriate delegation to approve without an admin session.
FieldTypeDescription
delegation_id requiredstringDelegation ID granting approval authority
approval_notestringOptional 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" }'
POST /api/v1/agent-workflow?id={workflow_id}&action=cancel
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

Agents cannot spend unlimited money or sign anything they want. Agent Trust gives each agent a controlled envelope for what it can see, negotiate, sign, and spend.

Per-API-key trust scoring, capability gating, and abuse protection determine transaction caps, allowed actions, approval thresholds, 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

LevelLabelTransaction CapCapabilitiesHow 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 /api/v1/agent-trust
Get the current agent’s trust level, score, capabilities, and progress towards the next level.
ParameterTypeDescription
actionstringhistory for trust level change log, locks for active capability locks
limitintegerMax 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, "success": true, "data": { "key_id": "key_abc123", "trust_level": 2, "trust_label": "Established", "trust_score": 62, "transaction_cap": 5000, "capabilities": { "discover": { "unlocked": true, "required_level": 0, "required_label": "Untrusted" }, "negotiate": { "unlocked": true, "required_level": 1, "required_label": "Provisional" }, "execute": { "unlocked": true, "required_level": 2, "required_label": "Established" }, "autonomous_workflow": { "unlocked": true, "required_level": 2, "required_label": "Established" }, "high_value_deals": { "unlocked": false, "required_level": 3, "required_label": "Trusted" }, "bulk_operations": { "unlocked": false, "required_level": 3, "required_label": "Trusted" }, "priority_support": { "unlocked": false, "required_level": 4, "required_label": "Verified Partner" } }, "progress": { "next_level": 3, "next_label": "Trusted", "score_required": 150, "score_current": 62, "score_percent": 41.3, "deals_required": 50, "days_required": 90, "max_failures_allowed": 5 } } }
GET /api/v1/agent-trust?action=history
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.

POST /api/v1/agent-trust-credentials?action=issue
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?action=issue" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{}'
Response
{ "error": false, "success": true, "data": { "credential_id": "cred_xyz789", "status": "active", "valid_from": "2026-03-12T10:00:00Z", "valid_until": "2026-06-10T10:00:00Z", "revoked_at": null, "revocation_reason": null, "credential": { "@context": [ "https://www.w3.org/2018/credentials/v1" ], "id": "did:web:api.salesbooth.com/credentials/cred_xyz789", "type": [ "VerifiableCredential", "AgentTrustCredential" ], "issuer": "did:web:api.salesbooth.com", "issuanceDate": "2026-03-12T10:00:00Z", "validFrom": "2026-03-12T10:00:00Z", "validUntil": "2026-06-10T10:00:00Z", "credentialSubject": { "id": "did:key:agent:key_abc123", "trustLevel": 2, "trustScore": 740, "dealsCompleted": 18, "disputeRate": 0, "businessVerified": true, "issuedAt": "2026-03-12T10:00:00Z" }, "proof": { "type": "Ed25519Signature2020", "created": "2026-03-12T10:00:00Z", "verificationMethod": "did:web:api.salesbooth.com#tenant_key_123", "proofPurpose": "assertionMethod", "proofValue": "base64-encoded-signature" } } } }
GET /api/v1/agent-trust-credentials
Export the current active verifiable credential for the authenticated agent.
Example
curl https://api.salesbooth.com/v1/agent-trust-credentials \ -H "Authorization: Bearer sb_test_example_key_do_not_use"

Agent registry

Use Agent Registry for same-tenant multi-agent coordination. It exposes summary-level discovery so agents can see active delegations, inspect high-level activity, and detect overlapping product work without leaking full workflow internals.

GET /api/v1/agent-registry?action={list_agents|agent_activity|check_contention}
Discover active agents, query activity, or check product contention. Requires agent:discover with bearer auth or API key auth; tenant session auth is also supported. Rate limits are trust-tiered.
ParameterTypeDescription
action requiredstringlist_agents, agent_activity, or check_contention
statusstringFor list_agents: active, expired, revoked, or all
capability_scopestringFilter listed delegations to those with a specific allowed action
created_afterdate-timeReturn delegations created after this ISO 8601 timestamp
limitintegerPagination limit for list_agents (default: 50, max: 100)
offsetintegerPagination offset for list_agents
delegation_idstringTarget delegation for agent_activity
agent_identifierstringAlternative target identifier for agent_activity
product_idsstringComma-separated product IDs for check_contention
Example — list active agents
curl "https://api.salesbooth.com/v1/agent-registry?action=list_agents&status=active&limit=20" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
Success shape: list_agents returns data.agents[] plus data.pagination; agent_activity returns per-agent workflow and spending summaries; check_contention returns data.contention[] and data.total_contested. Common errors: 400, 401, 403, 404, 429, and 500.

Public credential verification

Third parties can verify Salesbooth verifiable credentials without a seller API key. This is the public verification endpoint for compliance, financing, partner federation, and dispute review workflows.

POST /api/v1/verify
Verify the signature and status of a Salesbooth verifiable credential. Public endpoint — no authentication required. Rate limited to 30 requests per minute per IP.
FieldTypeDescription
credential requiredobjectW3C Verifiable Credential object to verify. Must include @context, type, and proof.
Example
curl -X POST https://api.salesbooth.com/v1/verify \ -H "Content-Type: application/json" \ -d '{ "credential": { "@context": ["https://www.w3.org/2018/credentials/v1"], "type": ["VerifiableCredential", "AgentTrustCredential"], "proof": { "type": "Ed25519Signature2020", "proofValue": "base64-encoded-signature" } } }'
Success shape: returns data.valid, data.status, and data.verified_at, with additional issuer, credential, and revocation metadata when available. Common errors: 400, 405, 429, and 500.

Trust-Related Webhook Events

agent.trust.level_changedTrust level promoted or demoted
agent.trust_cap_exceededAgent attempted a deal above their trust cap
agent.trust.abuse_detectedAnomalous behaviour detected — capability lock applied
agent.trust.credential_issuedVerifiable credential issued to agent
agent.trust.credential_revokedPreviously issued credential revoked

MCP Protocol

Connect ChatGPT, Claude, or your own agent to Salesbooth. Your agent can discover offers, negotiate, create deals, check rules, and complete purchases through controlled tools.

Salesbooth turns MCP into controlled agent commerce tools across 192 tools in 28 categories, so your agent can work with products, deals, contracts, payments, approvals, resources, and prompts without hand-coded REST calls for every action.

Salesbooth implements the Model Context Protocol (MCP) over HTTP using JSON-RPC 2.0. The MCP endpoint supports resource browsing, prompt templates, and subscriptions so agents can work with 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.

POST /api/v1/mcp
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.
HeaderDescription
AuthorizationBearer <api_key> — required. Use an API key with at minimum agent:discover scope.
X-Delegation-IDOptional delegation token ID to execute tools under a scoped delegation with spending limits.
Content-Typeapplication/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": ["fixed", "tiered", "volume", "usage"] }, "payment_terms": { "type": "string", "description": "Filter by payment terms (e.g. \"net_30\", \"net_60\")" }, "limit": { "type": "integer", "minimum": 1, "maximum": 100 }, "offset": { "type": "integer", "minimum": 0 } }, "required": [], "additionalProperties": false } } ] } }

Response excerpt; additional tools are omitted.

Tool Categories

CategoryDescription
agent_registryDiscover peer and child agents in the same tenant, query agent activity summaries, and detect product contention for multi-agent coordination
agent_trustCheck trust level, capabilities, and trust lock status for the current agent
auditView and verify audit trails for entities
billingCheck credit balance, trust level, and auto top-up configuration before planning workflows — enabling agents to pre-check affordability before committing to multi-step operations
catalog_managementWrite tools for product configuration schemas, pricing, bundle rules, compatibility rules, and option group management — enabling agents to act as autonomous product managers
closureAgent-executed deal closure: sign deals with Ed25519/HMAC, capture payments, verify signatures, and atomically close fully-signed and fully-paid deals
complianceGDPR operations and audit trail exports
configurationManage product families, option groups, and pricing rules
contractsCreate, sign, activate, and manage contracts
customer_managementCreate and manage customer records
deal_managementCreate, update, and manage deals through their full lifecycle
deal_participantsMulti-agent deal collaboration: invite agents with role assignments, manage scope completion, and view revenue sharing settlements
delegationsCreate and manage agent delegation permissions
documentsGenerate quotes and invoices from deals, send notifications to customers, and retrieve contact preferences — enabling agents to communicate structured offers autonomously
federationDiscover offerings on remote Salesbooth instances and negotiate deals across instances using the salesbooth-negotiate/1.0 protocol
headless_flowValidate configurations, preview payment amounts, and validate promo codes for headless widget sessions — enabling agents to orchestrate buyer-facing deal flows without a rendered widget UI
intelligenceAI-powered deal scoring, pricing analytics, and pipeline insights
negotiationPropose, counter, and resolve deal negotiations
paymentsProcess payments, refunds, and manual payment recordings
product_catalogBrowse, configure, and manage products and pricing
sandboxTest environment setup, seeding, and webhook simulation
saved_configsSave, share, and convert product configurations to deals
searchGlobal search across customers, products, deals, and contracts
subscriptionsManage recurring billing subscriptions
templatesCreate, clone, and instantiate deal templates
webhooksManage webhook endpoints and event delivery
widgetsConfigure and manage embeddable deal widgets
workflowsAutonomous deal orchestration with delegation-scoped execution

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": {} } }
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", "title": "Enterprise software package", "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", "name": "Platform Pro (Enterprise)", "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: deals:read)
{ "jsonrpc": "2.0", "id": "w2a", "method": "tools/call", "params": { "name": "score_deal", "arguments": { "deal_id": "deal_xyz789" } } }
Get pricing recommendations (scope: deals: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": "{\"suggested_price\":9500,\"confidence\":0.82,\"factors\":{\"volume_threshold\":\"reached\",\"market_position\":\"competitive\"}}" }], "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", "proposed_terms": { "discount_percent": 10, "payment_terms": "net_30" } } } }
Get negotiation history (scope: agent:negotiate)
{ "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", "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 The Product Catalog

Use an MCP-visible catalogue tool to discover products by keyword. Requires products:read scope.

Product search (scope: products:read)
{ "jsonrpc": "2.0", "id": "w5", "method": "tools/call", "params": { "name": "list_products", "arguments": { "search": "enterprise", "limit": 10 } } }
Response
{ "jsonrpc": "2.0", "id": "w5", "result": { "content": [{ "type": "text", "text": "{\"products\":[{\"product_id\":\"prod_platform_pro\",\"name\":\"Platform Pro (Enterprise)\",\"price\":4999.00},{\"product_id\":\"prod_support_plus\",\"name\":\"Support Plus\",\"price\":999.00}]}" }], "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": "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" }, { "uri": "salesbooth://billing/credits", "name": "Credit Balance", "mimeType": "application/json" }, { "uri": "salesbooth://trust/score-history", "name": "Trust Score History", "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 Detail", "mimeType": "application/json" }, { "uriTemplate": "salesbooth://products/{product_id}", "name": "Product Detail", "mimeType": "application/json" }, { "uriTemplate": "salesbooth://customers/{customer_id}", "name": "Customer Detail", "mimeType": "application/json" }, { "uriTemplate": "salesbooth://contracts/{contract_id}", "name": "Contract Detail", "mimeType": "application/json" }, { "uriTemplate": "salesbooth://templates/{template_id}", "name": "Template Detail", "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.", "arguments": [ { "name": "customer_id", "description": "Existing customer ID (optional — will prompt for creation if not provided)", "required": false }, { "name": "product_ids", "description": "Comma-separated product IDs to include in the deal", "required": false }, { "name": "currency", "description": "Deal currency (ISO 4217, e.g. USD, EUR). Defaults to tenant default.", "required": false } ] }, { "name": "negotiate-deal", "description": "Structured negotiation workflow: review current deal terms, apply intelligence scoring, propose or counter terms.", "arguments": [ { "name": "deal_id", "description": "The deal ID to negotiate on", "required": true }, { "name": "strategy", "description": "Negotiation strategy hint: \"aggressive\", \"balanced\", or \"conservative\"", "required": false } ] }, { "name": "configure-widget", "description": "Widget setup workflow: select a site, choose products, configure theme and steps, generate embed code.", "arguments": [ { "name": "site_id", "description": "Site ID to attach the widget to", "required": false }, { "name": "product_ids", "description": "Comma-separated product IDs to feature in the widget", "required": false } ] }, { "name": "review-pipeline", "description": "Pipeline health check: analyze deal distribution by status, identify bottlenecks, get recommended actions.", "arguments": [ { "name": "focus", "description": "Focus area: \"conversion\", \"revenue\", \"velocity\", or \"all\"", "required": false } ] }, { "name": "batch-deal-workflow", "description": "Atomic multi-step deal workflow: create deal, add line items, apply discount, and transition status in a single all-or-nothing transaction. Use this for autonomous agent deal execution to avoid orphaned deals on partial failure.", "arguments": [ { "name": "customer_id", "description": "Existing customer ID for the deal", "required": true }, { "name": "product_ids", "description": "Comma-separated product IDs to add as line items", "required": false }, { "name": "discount_percent", "description": "Optional discount percentage to apply (0-100)", "required": false }, { "name": "target_status", "description": "Target deal status after creation: \"in_progress\" (default) or \"pending_signature\"", "required": false } ] }, { "name": "manage-delegation", "description": "Create or update agent delegations: define scope, spending limits, and expiry for sub-agents.", "arguments": [ { "name": "grantee_agent_key_id", "description": "API key ID of the agent receiving delegation", "required": false }, { "name": "max_spend", "description": "Maximum spending limit for the delegation", "required": false } ] } ] } }

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": { "description": "Structured negotiation workflow: review current deal terms, apply intelligence scoring, propose or counter terms.", "messages": [ { "role": "user", "content": { "type": "text", "text": "You are negotiating deal `deal_xyz789` using a **balanced** strategy. Follow these steps:\n\n1. **Review current deal**: Use `check_deal_status` with id = `deal_xyz789` to see current terms, line items, and pricing.\n2. **Get intelligence**: Use `score_deal` with deal_id = `deal_xyz789` for AI scoring and pricing recommendations.\n3. **Check negotiation history**: Use `get_negotiation_history` with deal_id = `deal_xyz789` to see prior proposals and counters.\n4. **Propose or counter terms**: Based on the balanced strategy:\n - **aggressive**: Push for maximum value; counter with minimal concessions.\n - **balanced**: Find middle ground; match concessions proportionally.\n - **conservative**: Prioritize closing; offer reasonable discounts.\n Use `negotiate_terms` to submit your proposal.\n5. **Monitor response**: Check deal status for acceptance or further counter-proposals." } } ] } }

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 CodeMeaningRecovery
-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).

CategoryRequired Scopes
Deal Management agent:discover , deals:write , deals:read , 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 deals:read , deals:write
Product Configuration products:read , products:write
Saved Configurations deals:write , deals:read , agent:execute
Webhooks webhooks:read , webhooks:write
Delegations delegations:read , delegations:write
Compliance audit:export , customers:read , customers:write
Search search:read
Audit
Sandbox sandbox:write , sandbox:read
Agent Workflows agent:execute
Agent Trust agent:discover
Cross-Instance Federation agent:discover , agent:negotiate , agent:execute
Agent Registry agent:discover
Deal Participants deals:write , deals:read
Deal Closure deals:sign , deals:write , deals:read , agent:execute
Catalog Management products:write
Documents & Communications deals:write , customers:read
Billing & Credits billing:read
Headless Flow widgets: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.

ParameterValueMeaning
Request timeout10 secondsIndividual tool call must complete within 10 s or it fails
Failure threshold5 failuresCircuit opens after 5 consecutive failures in the window
Failure window60 secondsFailures older than 60 s are no longer counted
Recovery timeout30 secondsCircuit 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-discovery.json) 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 for GET status/audit and POST ?action=discover; agent:negotiate for POST ?action=send and ?action=negotiate; agent:execute for POST ?action=escrow, ?action=settle, and ?action=dispute.

Authentication: Requests are signed end-to-end with tenant Ed25519 key pairs. Remote instances validate incoming envelopes against the originator’s DID document at the issuer host’s /.well-known/did.json.

Actions (POST)

ActionRequired scopeDescription
discoveragent:discoverCross-instance product and deal discovery — find offerings available on a remote instance
sendagent:negotiateSend a signed negotiation envelope to a remote instance to initiate a deal
negotiateagent:negotiateReceive and process an incoming negotiation envelope from a remote instance
escrowagent:executeCoordinate matched escrow creation across both instances simultaneously
settleagent:executeInitiate 2-phase escrow settlement (PREPARE → COMMIT or ROLLBACK)
disputeagent:executeInitiate 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)
auditRetrieve 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?action=discover" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "instance": "partner.salesbooth.com", "filters": { "category": "software", "currency": "USD" } }'
Send a negotiation envelope
curl -X POST "https://api.salesbooth.com/v1/federation/negotiate?action=send" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "target_instance": "partner.salesbooth.com", "target_agent_id": "agent_partner_123", "type": "propose", "payload": { "deal_id": "deal_remote_123", "proposed_terms": { "discount_percent": 10, "currency": "USD" }, "expires_at": "" } }'
GET /api/v1/federation/negotiate
Return this instance’s federation capabilities manifest or retrieve the audit trail for a specific cross-instance transaction. Requires agent:discover scope.
ParameterTypeDescription
actionstringstatus (default) for capabilities manifest; audit to retrieve a transaction audit trail
xref_idstringCross-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"
POST /api/v1/federation/negotiate
Process a cross-instance negotiation action: discover remote offerings, send or receive negotiation envelopes, coordinate escrow, settle, or raise disputes. Requires the scope for the selected action; see table above.

Query parameter: action is required in the URL for POST requests, for example ?action=discover or ?action=send.

FieldTypeDescription
instancestringRemote instance hostname for action=discover (for example partner.salesbooth.com)
filtersobjectOptional discovery filters for action=discover, such as category or currency
target_instancestringRemote instance hostname for action=send
target_agent_idstringOptional remote agent identifier for action=send
typestringEnvelope type for action=send, such as propose, counter, accept, or reject
payloadobjectEnvelope payload for action=send
Example — discover remote offerings
curl -X POST "https://api.salesbooth.com/v1/federation/negotiate?action=discover" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "instance": "partner.salesbooth.com", "filters": { "category": "software", "currency": "USD" } }'
Example — send a negotiation envelope
curl -X POST "https://api.salesbooth.com/v1/federation/negotiate?action=send" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "target_instance": "partner.salesbooth.com", "target_agent_id": "agent_partner_123", "type": "propose", "payload": { "deal_id": "deal_remote_123", "proposed_terms": { "discount_percent": 10, "currency": "USD" }, "expires_at": "" } }'

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-discovery.json
GET /api/v1/federation/discovery?tenant_id={tenant_id}
Return the federation discovery manifest for a specific tenant. Public endpoint — no authentication required. Remote instances call this to retrieve the tenant’s federation protocol, instance metadata, capability flags, discovery endpoints, rate limits, and optional public Ed25519 key before initiating a cross-instance negotiation.
ParameterTypeDescription
tenant_id requiredstringTenant whose federation manifest to retrieve
Example
curl "https://api.salesbooth.com/v1/federation/discovery?tenant_id=tenant_xxxxx"
Response
{ "error": false, "success": true, "data": { "protocol": "salesbooth-negotiate/1.0", "instance": { "tenant_id": "tenant_xxxxx", "name": "Acme Renovations", "version": "1.0" }, "capabilities": { "discovery": true, "negotiation": true, "escrow": true, "signatures": true }, "catalog": { "product_count": 24, "deal_count": 8, "currencies": ["USD", "AUD"] }, "endpoints": { "discovery": "/api/v1/deal-discovery", "negotiate": "/api/v1/federation/negotiate", "public_key": "/api/v1/tenant/public-key" }, "rate_limits": { "discovery_per_minute": 30, "negotiate_per_minute": 10 }, "updated_at": "2026-07-02T02:12:05Z", "signing": { "algorithm": "ed25519", "key_id": "tsk_abc123def456", "public_key": "MCowBQYDK2VwAyEA7H4x5nN5mN7N8Qd3r2WjJ3l4J5k6L7m8N9p0Qr1sT2U=" } } }
GET /api/v1/tenant/public-key?tenant_id={tenant_id}
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.
ParameterTypeDescription
tenant_idstringTenant whose public key to retrieve (required if key_id not provided). Pass _current to resolve from session.
key_idstringRetrieve a specific signing key by ID (useful when verifying a signature that references a rotated key)
formatstringKey format: raw, pem, jwk, or all (default)
include_rotatedflagReturn 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, "success": true, "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: Signed cross-instance federation envelopes require the sending agent to be at least Trust Level 1 (Provisional). 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. If a specific federation action requires a higher trust level, that stricter gate must be enforced and documented on the endpoint itself.

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.

GET /api/v1/did-document?tenant_id={tenant_id}
Return the W3C DID document for a tenant. Public endpoint — no authentication required. The canonical API route requires tenant_id; the alternate /.well-known/did.json path only works on a host that maps to a single tenant domain. Includes the tenant’s Ed25519 verification method and service endpoints for federation, deal verification, and key rotation.
ParameterTypeDescription
tenant_idstringTenant whose DID document to retrieve on the canonical API route. This parameter is required for /api/v1/did-document.
Example
curl "https://api.salesbooth.com/v1/did-document?tenant_id=tenant_xxxxx"
Response
{ "error": false, "success": true, "data": { "@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.

GET /api/v1/federation-peers
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, "success": true, "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 } }
POST /api/v1/federation-peers
Register a new federation peer. Requires agent:execute scope.
FieldTypeDescription
hostname requiredstringHostname of the remote Salesbooth instance (e.g. partner.salesbooth.com)
remote_tenant_idstringTenant ID on the remote instance to federate with specifically
trust_levelintegerInitial trust level for this peer (0–5, default: 1)
statusstringactive 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, "success": true, "data": { "id": 1, "hostname": "partner.salesbooth.com", "remote_tenant_id": "tenant_yyyyy", "trust_level": 3, "status": "active" } }
PATCH /api/v1/federation-peers?id={peer_id}
Update a federation peer’s trust level or status. Requires agent:execute scope.
FieldTypeDescription
statusstringactive or suspended
trust_levelintegerNew 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, "success": true, "data": { "updated": true, "id": 1 } }
DELETE /api/v1/federation-peers?id={peer_id}
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, "success": true, "data": { "deleted": true, "id": 1 } }

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 validation_error.sandbox_only when called with a live API key (sb_live_*). Generate a test key from the API Keys page in your dashboard.

POST /api/v1/sandbox/reset
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, "success": true, "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." } }
POST /api/v1/sandbox/seed
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, "success": true, "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." } }
POST /api/v1/sandbox/simulate_webhook
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.
FieldDescription
event_type requiredEvent type to simulate (e.g. deal.created, deal.closed, payment.received)
dataCustom 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_type": "deal.closed", "data": { "deal_id": "deal_test_abc123", "total": "2500.00", "currency": "USD" } }'
Response
{ "error": false, "success": true, "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)." } }
GET /api/v1/sandbox/status
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, "success": true, "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.

POST /api/v1/playground/session
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, "success": true, "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 } }
GET /api/v1/playground/session
Check whether a playground session key is still valid. Pass the key prefix to look up its expiry status. No authentication required.
ParameterTypeDescription
key_prefix requiredstringUse the key_prefix returned by POST /api/v1/playground/session (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, "success": true, "data": { "valid": true, "expires_at": "2026-03-24T12:00:00Z", "reason": null } }

Widgets

Manage embedded deal widgets programmatically. Widgets are configured per-site with auto-generated publishable API keys and can be created manually or from deal templates.

GET /api/v1/widget-config
List all widget configurations for the authenticated tenant, or retrieve a specific widget by ID. Also supports public access via a publishable API key — no authentication required when using api_key.
ParameterDescription
idWidget ID to retrieve a specific widget. When omitted, returns the full list for the authenticated tenant.
api_keyPublishable API key (sb_pub_*) for public widget config access. No authentication required when using this parameter — this is the primary mechanism for embedded widgets to fetch their configuration client-side.
Example (authenticated list)
curl https://api.salesbooth.com/v1/widget-config \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
Example (public access via publishable key)
curl "https://api.salesbooth.com/v1/widget-config?api_key=sb_pub_xxxxxxxxxxxx"
Response (public access)
{ "error": false, "success": true, "data": { "widget_id": "wgt_xxxxxxxxxxxx", "title": "Get Started", "theme_color": "#2563eb", "currency": "USD", "merchant_available": true, "stripe_publishable_key": "pk_live_xxxxxxxxxxxx", "products": "prod_xxxxxxxxxxxx" } }
GET /api/v1/widget-config?id={widget_id}
Retrieve a specific widget configuration by ID (authenticated).
ParameterDescription
id requiredWidget ID to retrieve
Example
curl "https://api.salesbooth.com/v1/widget-config?id=wgt_xxxxxxxxxxxx" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{ "error": false, "success": true, "data": { "widget_id": "wgt_xxxxxxxxxxxx", "site_id": "site_xxxxxxxxxxxx", "title": "Get Started", "theme_color": "#2563eb", "currency": "USD", "products": "prod_xxxxxxxxxxxx", "api_key": "sb_pub_xxxxxxxxxxxx", "created_at": "2024-01-15T10:00:00Z", "updated_at": "2024-01-15T10:00:00Z" } }
GET /api/v1/widget-config?widget_id={widget_id}
Retrieve a public widget configuration for embeds, headless checkouts, or agent delivery flows. Public lookups resolve by publishable key or by widget_id; the authenticated id selector is not used in this mode.
ParameterDescription
api_keyPublishable API key (sb_pub_*) used to load the widget configuration tied to that key. Can also be sent via the Authorization: Bearer or X-API-Key header.
widget_idPublic widget ID lookup for callers that need a specific widget configuration without using the authenticated id selector.
Examples
curl "https://api.salesbooth.com/v1/widget-config?api_key=sb_pub_xxxxxxxxxxxx" curl "https://api.salesbooth.com/v1/widget-config?widget_id=wgt_xxxxxxxxxxxx" curl "https://api.salesbooth.com/v1/widget-config?widget_id=wgt_xxxxxxxxxxxx" \ -H "Authorization: Bearer sb_pub_xxxxxxxxxxxx"
POST /api/v1/widget-config
Create a new widget configuration. Auto-generates a publishable API key scoped to the site’s domain.
FieldDescription
Basic
site_id requiredThe site to attach the widget to
titleWidget display title (default: “Create a Deal”)
theme_colorPrimary theme colour as CSS hex (default: #2563eb)
currencyISO 4217 settlement currency code (default: USD). One of: USD, EUR, GBP, CAD, AUD, NZD, CHF, JPY, MXN, BRL
productsComma-separated product IDs available in the widget
cta_textCustom call-to-action button label
Appearance
dark_modeBoolean — enable dark colour scheme
logo_urlMerchant logo URL displayed in widget header
font_familyFont family name (web-safe or Google Font)
custom_cssCustom CSS injected into widget Shadow DOM (sanitised server-side)
border_radiusBorder radius in pixels, 0–16 (default: 12)
button_styleCTA button style: filled, outlined, or text
Negotiation
enable_negotiationBoolean — allow buyers to submit counter-offers
negotiation_modeNegotiation scope: price_only, item_selection, terms_only, or full
auto_accept_thresholdMinimum counter-offer percentage (0–100) to auto-accept
Payment
payment_typePayment collection mode: full, deposit, or quote
deposit_typeDeposit calculation method: fixed or percentage
deposit_valueDeposit amount (when fixed) or percentage 0–100 (when percentage)
deposit_noteNote about the remaining balance shown to the buyer
Steps
step_1_nameCustom semantic label for the Products step
step_2_nameCustom semantic label for the Configure step
step_3_nameCustom semantic label for the Summary step
step_4_nameCustom semantic label for the Negotiate step (8-step flow)
step_5_nameCustom semantic label for the Customer/Details step (8-step flow)
step_6_nameCustom semantic label for the Terms step (8-step flow)
step_7_nameCustom semantic label for the Payment step (8-step flow)
step_8_nameCustom semantic label for the Confirmation step (8-step flow)
booking_step_nameCustom semantic label for the Booking step when it is active
discount_step_nameCustom semantic label for the Discount step when it is active
step_orderCustom step ordering: comma-separated step names (e.g. products,summary,customer,payment,confirmation)
skip_stepsSteps to skip from default flow: comma-separated step names (payment and confirmation cannot be skipped)
step_conditionsConditional step visibility rules: JSON object mapping step names to conditions (minTotal, maxTotal, dealType)
Promotions
enable_promo_codesBoolean — allow buyers to enter promotional codes
enable_discount_stepBoolean — enable a dedicated discount step in the widget flow
auto_discountsAutomatic discount rules based on cart contents or quantity thresholds (object)
Templates
contract_template_idContract template used for terms shown to buyers
deal_template_idDeal template used to pre-populate the widget
Social Proof
show_social_proofBoolean — show purchase count indicators (default: true)
show_smart_defaultsBoolean — pre-select popular options as defaults (default: true)
social_proof_thresholdMinimum purchase count before social proof displays (1–100, default: 5)
show_stock_quantityBoolean — display remaining stock quantity next to products
Analytics
analytics_modeComma-separated analytics targets: gtm, ga4, segment, callback
analytics_callbackGlobal JS function name for custom analytics events
analytics_consentBoolean — require user consent before firing analytics (GDPR)
Localisation
localeWidget UI language code (e.g. en, en-AU, es, de, fr, ja)
locale_overridesCustom string overrides for widget i18n labels (object with dot-separated keys)
display_currenciesISO 4217 currency codes available for buyer display conversion (array of strings)
Product Selection
product_selection_modeWhether buyers can select one or multiple products: single or multiple (default: single)
saved_config_ttl_daysDays a buyer’s saved configuration is retained (1–365, default: 30)
Booking
booking_configWidget-level booking step configuration object: enable_booking, staff_ids, duration, availability_source, custom_hours, buffer_time, max_advance_days, confirmation
Network & Advanced
network_configNetwork and cache tuning object: fetch_timeout, retry_max, retry_base_delay, retry_max_delay, retry_jitter, total_retry_budget, cache_products_ttl, cache_config_ttl, cache_assets_ttl, negotiate_poll_interval, negotiate_sse_timeout, heartbeat_interval, heartbeat_offline_interval, abandon_timeout (milliseconds except retry_jitter). Legacy aliases timeout_ms, retry_attempts, max_retries, retry_delay_ms, and cache_ttl_seconds are still normalized for backward compatibility.
signature_modeContract signature capture method: checkbox, type, draw, or digital (default: checkbox)
PATCH /api/v1/widget-config?id={widget_id}
Partially update a widget configuration. Only provided fields are changed.
FieldDescription
Basic
titleWidget display title
theme_colorPrimary theme colour as CSS hex
currencyISO 4217 settlement currency code. One of: USD, EUR, GBP, CAD, AUD, NZD, CHF, JPY, MXN, BRL
productsComma-separated product IDs available in the widget
cta_textCustom call-to-action button label
Appearance
dark_modeBoolean — enable dark colour scheme
logo_urlMerchant logo URL displayed in widget header
font_familyFont family name (web-safe or Google Font)
custom_cssCustom CSS injected into widget Shadow DOM (sanitised server-side)
border_radiusBorder radius in pixels, 0–16 (default: 12)
button_styleCTA button style: filled, outlined, or text
Negotiation
enable_negotiationBoolean — allow buyers to submit counter-offers
negotiation_modeNegotiation scope: price_only, item_selection, terms_only, or full
auto_accept_thresholdMinimum counter-offer percentage (0–100) to auto-accept
Payment
payment_typePayment collection mode: full, deposit, or quote
deposit_typeDeposit calculation method: fixed or percentage
deposit_valueDeposit amount (when fixed) or percentage 0–100 (when percentage)
deposit_noteNote about the remaining balance shown to the buyer
Steps
step_1_nameCustom semantic label for the Products step
step_2_nameCustom semantic label for the Configure step
step_3_nameCustom semantic label for the Summary step
step_4_nameCustom semantic label for the Negotiate step (8-step flow)
step_5_nameCustom semantic label for the Customer/Details step (8-step flow)
step_6_nameCustom semantic label for the Terms step (8-step flow)
step_7_nameCustom semantic label for the Payment step (8-step flow)
step_8_nameCustom semantic label for the Confirmation step (8-step flow)
booking_step_nameCustom semantic label for the Booking step when it is active
discount_step_nameCustom semantic label for the Discount step when it is active
step_orderCustom step ordering: comma-separated step names (e.g. products,summary,customer,payment,confirmation)
skip_stepsSteps to skip from default flow: comma-separated step names (payment and confirmation cannot be skipped)
step_conditionsConditional step visibility rules: JSON object mapping step names to conditions (minTotal, maxTotal, dealType)
Promotions
enable_promo_codesBoolean — allow buyers to enter promotional codes
enable_discount_stepBoolean — enable a dedicated discount step in the widget flow
auto_discountsAutomatic discount rules based on cart contents or quantity thresholds (object)
Templates
contract_template_idContract template used for terms shown to buyers
deal_template_idDeal template used to pre-populate the widget
Social Proof
show_social_proofBoolean — show purchase count indicators
show_smart_defaultsBoolean — pre-select popular options as defaults
social_proof_thresholdMinimum purchase count before social proof displays (1–100)
show_stock_quantityBoolean — display remaining stock quantity next to products
Analytics
analytics_modeComma-separated analytics targets: gtm, ga4, segment, callback
analytics_callbackGlobal JS function name for custom analytics events
analytics_consentBoolean — require user consent before firing analytics (GDPR)
Localisation
localeWidget UI language code (e.g. en, en-AU, es, de, fr, ja)
locale_overridesCustom string overrides for widget i18n labels (object with dot-separated keys)
display_currenciesISO 4217 currency codes available for buyer display conversion (array of strings)
Product Selection
product_selection_modeWhether buyers can select one or multiple products: single or multiple
saved_config_ttl_daysDays a buyer’s saved configuration is retained (1–365)
Booking
booking_configWidget-level booking step configuration object: enable_booking, staff_ids, duration, availability_source, custom_hours, buffer_time, max_advance_days, confirmation
Network & Advanced
network_configNetwork and cache tuning object: fetch_timeout, retry_max, retry_base_delay, retry_max_delay, retry_jitter, total_retry_budget, cache_products_ttl, cache_config_ttl, cache_assets_ttl, negotiate_poll_interval, negotiate_sse_timeout, heartbeat_interval, heartbeat_offline_interval, abandon_timeout (milliseconds except retry_jitter). Legacy aliases timeout_ms, retry_attempts, max_retries, retry_delay_ms, and cache_ttl_seconds are still normalized for backward compatibility.
signature_modeContract signature capture method: checkbox, type, draw, or digital
Example
curl -X PATCH "https://api.salesbooth.com/v1/widget-config?id=wgt_xxxxx" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "theme_color": "#10b981", "cta_text": "Get a Quote", "enable_negotiation": true }'
DELETE /api/v1/widget-config?id={widget_id}
Delete a widget configuration and revoke its publishable API key. The embed code will stop working immediately.
Example
curl -X DELETE "https://api.salesbooth.com/v1/widget-config?id=wgt_xxxxx" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
POST /api/v1/widget-config/from-template
Generate a pre-filled widget configuration from a deal template. Reads the template’s product list, applies the same generated widget suggestion fields as auto-configure, and adds template metadata. Does not save — returns suggestions for the widget form to pre-fill.
FieldDescription
template_id requiredDeal template identifier (e.g. dtpl_xxxxx)
Example
curl -X POST https://api.salesbooth.com/v1/widget-config/from-template \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "template_id": "dtpl_abc123" }'
Response
{ "error": false, "success": true, "data": { "title": "Enterprise Starter Pack", "cta_text": "Get Started", "step_1_name": "Build Your Bundle", "step_2_name": "Configure", "step_3_name": "Review & Submit", "step_4_name": "Negotiate", "step_5_name": "Details", "step_6_name": "Terms", "step_7_name": "Payment", "step_8_name": "Done", "payment_type": "full", "products": "prod_1, prod_2", "currency": "USD", "deal_template_id": "dtpl_abc123", "template_name": "Enterprise Starter Pack" } }
POST /api/v1/widget-config/auto-configure
Generate a suggested widget configuration from a list of product IDs. Analyses the products and returns generated widget suggestion fields for title, call-to-action, step labels, payment type, and optional locale. Does not save — returns a configuration object for review before creating.
FieldTypeDescription
product_ids requiredarrayArray of product ID strings to base the configuration on
Example
curl -X POST "https://api.salesbooth.com/v1/widget-config/auto-configure" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "product_ids": ["prod_aaa", "prod_bbb"] }'
Response
{ "error": false, "success": true, "data": { "title": "Build Your Widgets Package", "cta_text": "Configure & Order", "step_1_name": "Build Your Bundle", "step_2_name": "Configure", "step_3_name": "Summary", "step_4_name": "Negotiate", "step_5_name": "Details", "step_6_name": "Terms", "step_7_name": "Payment", "step_8_name": "Done", "payment_type": "full", "locale": "en" } }
GET /api/v1/widget-config/embed-code
Get a ready-to-paste HTML embed snippet for a widget, including the <script> tag with SRI integrity attributes and the <salesbooth-deal> custom element. Also accessible as GET /api/v1/widget-config?id={id}&action=embed-code.
ParameterDescription
id requiredWidget identifier
Example
curl "https://api.salesbooth.com/v1/widget-config/embed-code?id=wgt_xxxxx" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{ "error": false, "success": true, "data": { "html": "<!-- Salesbooth Deal Widget -->\n<script src=\"...\" integrity=\"sha384-...\" crossorigin=\"anonymous\"></script>\n<salesbooth-deal api-key=\"sb_pub_xxxxx\"></salesbooth-deal>", "integrity": "sha384-...", "sdk_url": "https://salesbooth.com/sdk/v1/salesbooth-widget.js" } }

SDK Usage

const sb = Salesbooth.init({ apiKey: 'sb_test_example_key_do_not_use' }); // List all widgets const { widgets } = await sb.widgets.list(); // Create a widget from a deal template const config = await sb.widgets.createFromTemplate('dtpl_abc123', null, { theme_color: '#10b981' }); // Get the embed code for a widget const { html } = await sb.widgets.getEmbedCode('wgt_xxxxx'); document.getElementById('widget-container').innerHTML = html;

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 and conversions are limited to 10 per minute 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.

POST /api/v1/saved-configs
Save a product configuration snapshot. Returns a short code and shareable URL.
FieldDescription
product_selections requiredArray of product selections. Each item has product_id, name, quantity, configured_price, and an optional configuration object containing the selected option and modifier state for that product
pricing_snapshot requiredPricing breakdown object (subtotals, discounts, taxes at time of configuration)
option_selectionsObject mapping product IDs to their selected option values
subtotalTotal price as a number
currencyISO 4217 currency code (default: USD)
customer_nameBuyer name (optional)
customer_emailBuyer email (optional)
customer_phoneBuyer phone number (optional)
customer_custom_fieldsObject of custom field key-value pairs collected from the buyer during configuration (optional)
booking_selectionsObject with booking slot selections (optional)
expires_inExpiration in days, 1–365 (default: 30)
widget_idWidget ID to associate this configuration with. Used to resolve TTL and display settings. Inferred from the publishable key context; supply explicitly when authenticating with a secret API key (optional)
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" } }
GET /api/v1/saved-configs?code={short_code}
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.
ParameterDescription
code requiredThe 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": [ { "product_id": "prod_renovation_consult", "quantity": 1, "option_ids": ["opt_priority_booking"] } ], "pricing_snapshot": { "subtotal": 99, "discount_total": 0, "tax_total": 0, "total": 99 }, "subtotal": 99.00, "currency": "USD", "expired": false, "expires_at": "2026-03-22 14:30:00", "share_url": "https://salesbooth.com/configure/a3f8b21c", "price_changes": [] } }
PATCH /api/v1/saved-configs?id={short_code}
Update mutable fields of a saved configuration. Authenticated with a publishable API key (sb_pub_*).
FieldDescription
customer_nameBuyer name
customer_emailBuyer email address
customer_phoneBuyer phone number
option_selectionsObject mapping product IDs to their selected option values
booking_selectionsObject 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" }'
DELETE /api/v1/saved-configs?id={short_code}
Permanently delete a saved configuration by its short code. Requires a secret API key (sb_test_* or sb_live_*). Publishable keys are not accepted for this operation.
Example
curl -X DELETE "https://api.salesbooth.com/v1/saved-configs?id=a3f8b21c" \ -H "Authorization: Bearer sb_test_xxxxx"
POST /api/v1/saved-configs?action=to_deal
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. Supply customer_name and customer_email only to override saved buyer details; conversion still needs an effective name and email from either the saved configuration or the request body. Returns 409 if already converted, 410 if expired.
FieldDescription
short_code requiredThe short code of the saved configuration
customer_nameOptional buyer name override; falls back to the saved value when omitted
customer_emailOptional buyer email override; falls back to the saved value when omitted
customer_phoneBuyer 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": { "deal_id": "deal_xxxxx", "status": "draft", "currency": "USD", "total": 99 }, "converted_from": "a3f8b21c" } }

Widget Analytics

Track widget conversion funnels and user engagement. Record events from embedded widgets and retrieve aggregated metrics.

POST /api/v1/widget-analytics
Record a widget analytics event using the canonical funnel event names emitted by the widget.
FieldTypeDescription
api_keystringWidget publishable API key. Optional when using Authorization: Bearer sb_pub_*.
session_id requiredstringUnique session identifier
event_type requiredstringEvent type: impression, step-change, product-selected, customer-entered, payment-started, deal-created, payment-completed, abandoned, error, terms-accepted, transition-warning
stepstringCurrent step name
dataobjectAdditional event data
Example
curl -X POST https://api.salesbooth.com/v1/widget-analytics \ -H "Content-Type: application/json" \ -d '{ "api_key": "sb_pub_xxxxx", "session_id": "sess_abc123", "event_type": "step-change", "step": "product_selection", "data": { "from": "landing", "to": "product_selection", "stepName": "Product selection" } }'
GET /api/v1/widget-analytics
Retrieve aggregated analytics for a widget — views, conversion rates, and funnel drop-off. Omit widget_id to return tenant-wide analytics for the authenticated tenant.
ParameterTypeDescription
widget_idstringOptional widget identifier filter. Omit to return tenant-wide analytics.
daysintegerOptional lookback period in days (default: 30)
Example
curl "https://api.salesbooth.com/v1/widget-analytics?widget_id=wgt_xxxxx&days=7" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"

Session replay collection

Use the replay collector for browser session recordings and event playback tied to a tenant website domain. This endpoint is public, but each request must identify the originating host so Salesbooth can resolve the correct site.

POST /api/v1/collect
Collect base64-encoded session replay payloads from SDK clients. No authentication required. Requires a customer host that matches a configured site domain and returns 204 No Content on success.
FieldTypeDescription
session_id requiredstringClient session identifier used to append events to the same replay stream
enc requiredstringEncoding marker. Must be b64.
data requiredstringBase64-encoded JSON object containing an events array
host requiredstringCustomer website domain the replay originated from
timezonestringOptional client timezone stored with the replay session
Example
curl -X POST https://api.salesbooth.com/v1/collect \ -H "Content-Type: application/json" \ -d '{ "session_id": "sess_abc123", "enc": "b64", "host": "example.com", "data": "eyJldmVudHMiOlt7InR5cGUiOiJwYWdlX3ZpZXciLCJ0cyI6MTcyMDEzMDAwMH1dfQ==", "timezone": "Australia/Sydney" }'
Responses: 204 accepted, 400 invalid payload, 404 unknown host, 413 body too large, 429 rate limited, and 500 write failure.

Uploads

Upload image files for products, option swatches, and other assets.

POST /api/v1/uploads
Upload an image file. Accepts JPEG, PNG, GIF, WebP, and SVG 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 (200)
{ "error": false, "success": true, "data": { "url": "/uploads/tenant_abc123/7f3c9a12d4e6b8c0f1a2d3e4b5c6d7e8.jpg", "filename": "7f3c9a12d4e6b8c0f1a2d3e4b5c6d7e8.jpg", "size": 145280, "mime_type": "image/jpeg" } }

Credits

Prepaid credit balance management. Check balance, top up via hosted checkout, view ledger history, and estimate deal costs.

GET /api/v1/credits
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 /api/v1/credits?action=ledger
Get credit ledger history showing all credit and debit transactions.
ParameterTypeDescription
limitintegerMax results (default: 25)
offsetintegerPagination offset
typestringFilter: 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"
GET /api/v1/credits?action=summary
Return an MCP-friendly credit summary including trust level, auto top-up configuration, and estimated remaining deal capacity. Requires billing:read scope.
Example
curl https://api.salesbooth.com/v1/credits?action=summary \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
Response
{ "error": false, "success": true, "data": { "credit_balance": 5000, "trust_level": 1, "trust_level_label": "Verified", "auto_topup_enabled": false, "auto_topup_ceiling": null, "cost_per_deal": 1, "estimated_remaining_deals": 5000, "can_create_deals": true } }
POST /api/v1/credits?action=topup
Create a hosted checkout session to top up credits.
FieldTypeDescription
amount requirednumberTop-up amount in USD (min: $5, max: $10,000)
success_url requiredstringRedirect URL on success
cancel_url requiredstringRedirect 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": 100, "success_url": "https://example.com/success", "cancel_url": "https://example.com/cancel" }'
POST /api/v1/credits?action=estimate
Return the tenant's current fixed per-deal credit estimate before processing. The current implementation does not inspect deal-specific inputs.
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 '{}'
POST /api/v1/credits?action=set-threshold
Update the low-balance warning threshold for prepaid credits. Requires billing:write scope.
FieldTypeDescription
threshold requirednumberLow-balance warning threshold in USD
Example
curl -X POST https://api.salesbooth.com/v1/credits?action=set-threshold \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "threshold": 250 }'

USDC

USDC is the tenant prepaid balance rail for agent spending on Base. It is separate from Stripe card collection and supports wallet setup, Coinbase-hosted deposits, and transaction history.

GET /api/v1/usdc?action={balance|transactions}
Return the current USDC balance and account summary by default, or a paginated transaction ledger when action=transactions. Requires billing:read; tenant session auth is also supported.
ParameterTypeDescription
actionstringbalance (default) or transactions
pageintegerTransactions page number (default: 1)
per_pageintegerTransactions page size (default: 20, max: 100)
Example
curl "https://api.salesbooth.com/v1/usdc?action=balance" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
Success shape: action=balance returns data.usdc_balance, data.wallet_address, chain metadata, and data.recent_charges[]. action=transactions returns data.transactions[] with pagination fields. Common errors: 400, 401, 403, 405, 413, and 500.
POST /api/v1/usdc?action={create-charge|set-wallet}
Create a Coinbase-hosted USDC deposit charge or store a verified Ethereum wallet address. Requires billing:write; tenant session auth is also supported.
Field / ParameterTypeDescription
action requiredquery stringcreate-charge or set-wallet
amountnumberRequired for create-charge. Deposit amount in USDC, subject to the tenant minimum deposit.
wallet_addressstringRequired for set-wallet. Ethereum wallet address (0x + 40 hex chars).
Example — create charge
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": 25 }'
Example — set wallet
curl -X POST "https://api.salesbooth.com/v1/usdc?action=set-wallet" \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "wallet_address": "0x1234567890abcdef1234567890abcdef12345678" }'
Responses: 201 for create-charge with charge_id, charge_code, hosted_url, amount_usdc, and expires_at; 200 for set-wallet with the normalised wallet_address. Common errors: 400, 401, 402, 403, 405, 413, 503, and 500.

Billing

Billing dashboard endpoints for credit balance, usage charts, transaction ledger, invoices, auto top-up configuration, and alert settings.

GET /api/v1/billing
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 /api/v1/billing?action=usage-daily
Get daily usage data for charts and trend analysis.
ParameterTypeDescription
daysintegerLookback 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"
POST /api/v1/billing?action=auto-topup
Configure automatic credit top-up. When enabling, first call action=setup-intent to save a saved payment method, then submit the resulting payment_method_id.
FieldTypeDescription
enabled requiredbooleanEnable or disable auto top-up
amountintegerCredits to purchase on trigger
payment_method_idstringSaved saved payment method ID from a completed setup intent
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, "amount": 500, "payment_method_id": "pm_123456789" }'
POST /api/v1/billing?action=alert-settings
Configure low-balance alert notifications.
FieldTypeDescription
thresholdintegerAlert when balance drops below this amount
email_enabledbooleanEnable or disable email alerts
webhook_enabledbooleanEnable or disable webhook alerts
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 '{ "threshold": 50, "email_enabled": true }'
GET /api/v1/billing?action=ledger
Retrieve paginated credit transaction history for the tenant.
ParameterTypeDescription
limitintegerNumber of entries per page (default: 25, max: 100)
offsetintegerOffset for pagination (default: 0)
typestringFilter 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"
GET /api/v1/billing?action=export-ledger
Export the credit ledger as a CSV download.
ParameterTypeDescription
typestringFilter 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"
GET /api/v1/billing?action=invoices
Retrieve a paginated list of invoices for the tenant.
ParameterTypeDescription
limitintegerNumber of invoices per page (default: 25, max: 100)
offsetintegerOffset 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"
GET /api/v1/billing?action=invoice-pdf
Download a specific invoice as a text/html document suitable for browser rendering, printing, or PDF generation.
ParameterTypeDescription
id requiredstringInvoice 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"
GET /api/v1/billing?action=auto-topup-log
Retrieve the paginated audit log of automatic top-up events.
ParameterTypeDescription
limitintegerNumber of entries per page (default: 25, max: 100)
offsetintegerOffset 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"
POST /api/v1/billing?action=topup
Create a hosted checkout session to add credits to the account.
FieldTypeDescription
amount requirednumberTop-up amount in USD (min: $5, max: $10,000)
success_url requiredstringURL to redirect to after successful payment
cancel_url requiredstringURL 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" }'
POST /api/v1/billing?action=setup-intent
Create a payment 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.

GET /api/v1/team
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"
POST /api/v1/team
Invite a new team member via email.
FieldTypeDescription
email requiredstringEmail address to invite
role requiredstringadmin, 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" }'
PATCH /api/v1/team
Update a team member’s role.
FieldTypeDescription
membership_id requiredintegerTeam membership identifier
role requiredstringNew 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": 42, "role": "admin" }'
DELETE /api/v1/team?id={membership_id}
Remove a team member.
Example
curl -X DELETE "https://api.salesbooth.com/v1/team?id=42" \ -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 /api/v1/trust
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, "success": true, "data": { "trust_level": 2, "trust_label": "Established", "trust_score": 85, "trust_level_changed_at": "2026-06-12 09:30:00", "ceiling": 10000, "auto_topup": { "enabled": true, "amount": 500, "ceiling": 10000, "monthly_used": 1500, "monthly_remaining": 8500 }, "progress": { "next_level": 3, "next_label": "Trusted", "next_ceiling": 500, "requirements": { "score": { "current": 85, "required": 150, "met": false }, "days_active": { "current": 45, "required": 90, "met": false }, "deals_closed": { "current": 12, "required": 50, "met": false }, "max_disputes": { "required": 5 } } } } }
GET /api/v1/trust?action=history
Get the history of trust level changes for the tenant.
ParameterTypeDescription
limitintegerMax results (default: 50)
offsetintegerPagination offset
Example
curl https://api.salesbooth.com/v1/trust?action=history \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
GET /api/v1/trust/revocations?tenant_id={tenant_id}
Retrieve the list of revoked agent credentials and trust demotions for a tenant. Public endpoint — no authentication required, but requests must be tenant-scoped with tenant_id. Remote instances call this during federation to verify that incoming credentials have not been revoked since issuance.
ParameterTypeDescription
tenant_idstringRequired tenant ID whose revocation list should be returned
Example
curl "https://api.salesbooth.com/v1/trust/revocations?tenant_id=tenant_abc123"
Response
{ "error": false, "success": true, "data": { "issuer": "did:web:example.salesbooth.com", "type": "AgentTrustRevocationList", "revoked_credentials": [ { "credential_id": "cred_abc123", "revoked_at": "2026-02-10T08:00:00Z", "revocation_reason": "trust_demotion" } ], "count": 1, "updated_at": "2026-03-18T12:00:00Z" } }

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:readRequired for data export, consent retrieval, erasure verification, dashboard, and processing register
customers:writeRequired 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.

GET /api/v1/gdpr/export
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.
ParameterTypeDescription
customer_id requiredstringThe 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"
DELETE /api/v1/gdpr/erase
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.
ParameterTypeDescription
customer_id requiredstringThe customer identifier
Body FieldTypeDescription
reasonstringReason 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"}'
DELETE /api/v1/gdpr/full_erase
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.
ParameterTypeDescription
customer_id requiredstringThe customer identifier
Body FieldTypeDescription
reasonstringReason 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"}'
GET /api/v1/gdpr/verify
Verify that a customer’s data has been completely erased. Scans all tables for remaining PII and returns a verification report.
ParameterTypeDescription
customer_id requiredstringThe 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.

GET /api/v1/gdpr/consent
Retrieve consent records for a customer. Returns all consent entries with their current status and the list of valid consent purposes.
ParameterTypeDescription
customer_id requiredstringThe customer identifier
active_onlystringSet 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"
POST /api/v1/gdpr/consent
Record a new consent grant for a customer and purpose. Supports optional channel and consent version metadata.
FieldTypeDescription
customer_id requiredstringThe customer identifier
purpose requiredstringProcessing purpose (e.g. marketing, analytics, necessary)
channelstringHow consent was collected (default: api)
metadataobjectAdditional context about the consent
consent_versionstringVersion 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" }'
DELETE /api/v1/gdpr/consent
Withdraw an existing consent record for a customer and purpose.
ParameterTypeDescription
customer_id requiredstringThe customer identifier
Body FieldTypeDescription
purpose requiredstringThe 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"}'
POST /api/v1/gdpr/consent_withdraw_all
Batch withdraw all active consent records for a customer in a single operation.
FieldTypeDescription
customer_id requiredstringThe customer identifier
reasonstringReason 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"}'
POST /api/v1/gdpr/consent_renew
Extend the expiration of an existing consent record for a customer and purpose. Creates a new audit entry distinct from the initial grant.
FieldTypeDescription
customer_id requiredstringThe customer identifier
purpose requiredstringThe consent purpose to renew
channelstringRenewal channel (default: api)
expiration_monthsintegerCustom 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}'
POST /api/v1/gdpr/consent_renew_all
Renew all active or expired (non-withdrawn) consents for a customer in a single operation.
FieldTypeDescription
customer_id requiredstringThe customer identifier
channelstringRenewal 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"}'
GET /api/v1/gdpr/consent_expiring
Returns consent records that will expire within the specified number of days. Useful for triggering re-consent campaigns before expiry.
ParameterTypeDescription
days_aheadintegerLook-ahead window in days (default: 30, max: 365)
limitintegerMaximum 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"
GET /api/v1/gdpr/consent_health
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"
GET /api/v1/gdpr/consent_expiration_config
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"
POST /api/v1/gdpr/consent_expiration_config
Set the default expiration period for a specific consent purpose for the current tenant.
FieldTypeDescription
purpose requiredstringThe consent purpose to configure
expiration_months requiredintegerExpiration 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}'
GET /api/v1/gdpr/consent_purposes
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.

GET /api/v1/gdpr/retention
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"
PATCH /api/v1/gdpr/retention
Creates or updates a data retention policy for a specific data type.
FieldTypeDescription
data_type requiredstringThe data type to configure retention for
retention_days requiredintegerNumber of days to retain data
is_activebooleanWhether 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.

GET /api/v1/gdpr/dashboard
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"
GET /api/v1/gdpr/register
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"
GET /api/v1/gdpr/erasure_log
Returns paginated list of erasure and export audit log entries for the current tenant.
ParameterTypeDescription
offsetintegerNumber of entries to skip (default: 0)
limitintegerMaximum 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"
GET /api/v1/gdpr/search
Search customers by name, email, or ID using blind indexes, and overlay compliance context per result: active consent count and consent purposes held.
ParameterTypeDescription
q requiredstringSearch query (name, email, or customer ID)
limitintegerMaximum 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"
GET /api/v1/gdpr/audit_evidence
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.
ParameterTypeDescription
date_fromstringStart of date range, YYYY-MM-DD (defaults to 30 days ago)
date_tostringEnd 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.

GET /api/v1/gdpr/compliance_evidence
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", "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. Allowed values are verified, broken, and unavailable. A broken status triggers an immediate security review.

Webhook Signature Verification

Every webhook delivery includes an X-Salesbooth-Signature header (HMAC-SHA256 of timestamp + "." + raw body) and an X-Salesbooth-Timestamp header (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 const expectedBuf = Buffer.from(expected); const signatureBuf = Buffer.from(signature); if (expectedBuf.length !== signatureBuf.length || !crypto.timingSafeEqual(expectedBuf, signatureBuf)) { 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 the X-Salesbooth-Delivery-Id header 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.

POST /api/v1/customer-auth?action=request-access
Send a magic-link login email to a customer. Returns 200 regardless of whether the email exists to prevent enumeration.
FieldTypeDescription
email requiredstringCustomer 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": { "success": true, "message": "If an account exists with this email, a login link has been sent." } }
POST /api/v1/customer-auth?action=verify
Exchange a magic-link token (from the email link) for a JWT access token and refresh token.
FieldTypeDescription
token requiredstringOne-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", "token_type": "Bearer", "expires_in": 3600 } }
POST /api/v1/customer-auth?action=refresh
Refresh an expired access token using the refresh token.
FieldTypeDescription
refresh_token requiredstringRefresh token from the verify response
POST /api/v1/customer-auth?action=logout
Revoke the current customer session. Send Authorization: Bearer <customer_jwt> and omit the JSON body.

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.

GET /api/v1/customer-portal?action=my-deals
List all deals belonging to the authenticated customer.
ParameterTypeDescription
statusstringFilter by deal status
limitintegerMax results (default: 20)
offsetintegerPagination offset
GET /api/v1/customer-portal?action=deal&id={deal_id}
Get full deal details including line items, terms, and current status.
GET /api/v1/customer-portal?action=contract&deal_id={deal_id}
Retrieve the signed contract document for a deal.
POST /api/v1/customer-portal?action=sign
Digitally sign a contract to accept the deal terms.
FieldTypeDescription
deal_id requiredstringDeal to sign
signature_name requiredstringCustomer’s full name as signature
agreed requiredbooleanMust be true to accept terms
POST /api/v1/customer-portal?action=create-payment-intent
Create a payment intent for a deal. Returns the client_secret needed by the payment form to complete the payment on the buyer’s side.
FieldTypeDescription
deal_id requiredstringDeal to pay for
POST /api/v1/customer-portal?action=confirm-payment
Confirm payment completion after the payment form has collected and processed payment details.
FieldTypeDescription
deal_id requiredstringDeal identifier
payment_intent_id requiredstringpayment intent ID
GET /api/v1/customer-portal?action=profile
Get the customer’s own profile data.
PATCH /api/v1/customer-portal?action=profile
Update the customer’s profile fields.
FieldTypeDescription
namestringDisplay name
emailstringEmail address
phonestringPhone number
companystringCompany name
citystringCity
statestringState or region
zipstringPostal code
countrystringCountry
GET /api/v1/customer-portal?action=my-subscriptions
List all active and past recurring subscriptions for the customer.
GET /api/v1/customer-portal?action=portal-config&deal_id={deal_id}
Retrieve portal configuration for a deal, including the payment publishable key and whether payments are enabled for the tenant. Used by the embedded customer portal to initialise the payment form.
ParameterTypeDescription
deal_id requiredstringDeal 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 } }
GET /api/v1/customer-portal?action=consents
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 } ] } }
POST /api/v1/customer-portal?action=request-changes
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.
FieldTypeDescription
deal_id requiredstringDeal to request changes for
messagestringDescription 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" } }
POST /api/v1/customer-portal?action=consent-renew
Renew a specific consent by purpose. Extends the consent expiry date to the tenant-configured renewal period.
FieldTypeDescription
purpose requiredstringConsent 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" } }
POST /api/v1/customer-portal?action=consent-renew-all
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 AI assistant and other MCP-compatible agents. See MCP Protocol.

GET /api/v1/deal-discovery
Discover agent-visible deal offers with optional filters. Returns only products and deals that the merchant has explicitly enabled for agent discovery.
ParameterTypeDescription
categorystringFilter by product category
min_pricenumberMinimum deal price
max_pricenumberMaximum deal price
currencystringISO 4217 currency code (e.g. USD)
pricing_modelstringFilter by pricing model type
limitintegerMax results (default: 50, max: 100)
offsetintegerPagination 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", "status": "in_progress", "total": "2999.00", "currency": "USD", "category": "software", "structured_terms": null, "line_item_count": 3, "metadata": null, "created_at": "2026-03-15T10:30:00Z" } ], "pagination": { "total": 42, "limit": 50, "offset": 0, "count": 1 } } }

Structured deal terms schema: Use GET /api/v1/schema/deal-terms from Machine-Readable Schemas when validating deal_terms payloads for negotiation and set-terms flows.

Quotes & Invoices

Generate shareable quotes and invoices from deals. Quotes have a configurable validity window; invoices are permanent records. Customer-facing quote access happens through the public share_url viewer or the read-only short-code lookup endpoint, while seller API retrieval and listing stay behind authenticated quote endpoints.

Required scope: deals:write to generate quotes and invoices. Seller API quote listing and retrieval require deals:read. Anonymous customer quote reads are limited to GET /api/v1/quotes/by-code?short_code=... and the public /quote/{short_code} viewer URL returned in share_url.

POST /api/v1/quotes?action=generate_quote
Generate a quote from a deal. Returns a short code and shareable URL the customer can visit to view and accept the quote.
FieldTypeDescription
deal_id requiredstringDeal to generate quote for
validity_daysintegerDays 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" } }
POST /api/v1/quotes?action=generate_invoice
Generate a formal invoice from a closed deal.
FieldTypeDescription
deal_id requiredstringClosed deal to invoice

Public quote viewer: Customers open the generated share_url in a browser at /quote/{short_code}. For JSON-based customer experiences, use the unauthenticated /api/v1/quotes/by-code?short_code={short_code} alias. Seller integrations should continue using the authenticated /api/v1/quotes endpoints for listing and retrieval.

GET /api/v1/quotes/by-code?short_code={short_code}
Retrieve the customer-facing quote snapshot by short code without authentication. This mirrors the share-link data shown in the public quote viewer and does not expose internal seller-only identifiers.
GET /api/v1/quotes?deal_id={deal_id}
List all quotes generated for a deal. Requires authentication.
DELETE /api/v1/quotes?id={quote_id}
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.
ParameterTypeDescription
id requiredstringQuote 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 /api/v1/deal-notifications?customer_id={id}
Get a customer’s notification channel preferences and recent notification history before sending.
ParameterTypeDescription
customer_id requiredstringCustomer to check
Response
{ "error": false, "success": true, "data": { "preferred_channel": "email", "has_email": true, "has_phone": false, "marketing_consent": true, "recent_notifications": [ { "type": "quote_sent", "channel": "email", "sent_at": "2026-03-18T10:00:00Z" } ] } }
POST /api/v1/deal-notifications
Send a transactional notification to a customer about a deal.
FieldTypeDescription
deal_id requiredstringRelated deal
type requiredstringquote_sent, invoice_sent, payment_reminder, deal_update, terms_updated
messagestringOptional 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 scopes: products:read for POST simulations and comparisons; deals:read for GET negotiation-history analytics.

POST simulation and comparison pricing payloads include "simulation_only": true on each priced result to confirm no data was written. GET negotiation-history analytics returns aggregate analytics and does not include that flag.

POST /api/v1/simulate-pricing
Simulate bundle pricing for a cart. Applies all matching bundle discount rules and promo codes without creating a deal.
FieldTypeDescription
items requiredarrayArray of { product_id, quantity, option_ids? }
currencystringISO 4217 code (default: USD)
promo_codestringOptional promo code to test
auto_discountsarrayOptional auto-discount definitions: { type?, value, description?, min_subtotal? }. Supports up to 20 entries for widget-style discount simulation.
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", "auto_discounts": [ { "type": "percentage", "value": 10, "description": "Widget 10% off carts over $300", "min_subtotal": 300 } ] }'
Response
{ "error": false, "success": true, "data": { "items": [ { "product_id": "prod_aaa", "quantity": 2, "line_subtotal": 300 }, { "product_id": "prod_bbb", "quantity": 1, "line_subtotal": 150 } ], "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 } }
POST /api/v1/simulate-pricing/compare
Compare pricing across multiple cart scenarios side-by-side. Useful for agents presenting options to buyers.
FieldTypeDescription
scenarios requiredarrayArray of { label, items } scenario objects
currencystringISO 4217 currency code
GET /api/v1/simulate-pricing
Retrieve aggregated negotiation patterns for a product or category. Returns win rates, average discount depth, and deal velocity to inform agent negotiation strategy.

Required filter: Provide either product_id or category. Requests with only period_days are rejected with 400 Either product_id or category is required.

ParameterTypeDescription
product_idstringAnalyse patterns for a specific product. Required when category is omitted.
categorystringAnalyse patterns for a product category. Required when product_id is omitted.
period_daysintegerLookback window in days (1–365, default: 90)
Example (curl)
curl "https://api.salesbooth.com/v1/simulate-pricing?product_id=prod_123&period_days=90" \ -H "Authorization: Bearer sb_test_example_key_do_not_use"

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.

GET /api/v1/events/stream
Open a Server-Sent Events stream. Set Accept: text/event-stream and keep the connection open to receive events as they occur.
ParameterTypeDescription
eventsstringComma-separated event types to subscribe to (e.g. deal.updated,negotiation.countered). Omit for all.
deal_idstringFilter events to a specific deal
customer_idstringFilter events for a specific customer
last_event_idstringResume 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.

Widget A/B Tests

Run controlled experiments across two widget variants to optimise conversion. Traffic is split between the original widget (Variant A) and a challenger (Variant B) with configurable traffic weighting. Statistical significance is computed automatically.

Required scope: deals:read (GET), deals:write (POST/PATCH)

Public resolve endpoint: GET /api/v1/ab-tests/resolve?api_key=sb_pub_... — called by the widget loader on each page load to determine which variant to show. Requires a publishable key (sb_pub_*) via Authorization: Bearer, X-API-Key, or the query parameter shown.

GET /api/v1/ab-tests
List A/B tests for the tenant, or retrieve a specific test with live statistics including chi-squared significance and per-variant revenue.
ParameterTypeDescription
idstringRetrieve a specific test with full stats
Example
curl https://api.salesbooth.com/v1/ab-tests \ -H "Authorization: Bearer sb_test_example_key_do_not_use"
POST /api/v1/ab-tests
Create a new A/B test for a widget. A second variant widget is automatically cloned from the source with the provided overrides applied.
FieldTypeDescription
widget_id requiredstringSource (Variant A) widget
namestringDescriptive test name (auto-generated from widget title if omitted)
traffic_weight_bintegerPercentage of traffic to send to Variant B (default: 50)
auto_promotebooleanAuto-promote winner when significance threshold is reached
variant_b_titlestringOverride widget title for Variant B
variant_b_cta_textstringOverride CTA button text for Variant B
variant_b_theme_colorstringOverride theme colour hex for Variant B
Example
curl -X POST https://api.salesbooth.com/v1/ab-tests \ -H "Authorization: Bearer sb_test_example_key_do_not_use" \ -H "Content-Type: application/json" \ -d '{ "widget_id": "wgt_xxxxx", "name": "CTA Button Colour Test", "traffic_weight_b": 50, "auto_promote": true, "variant_b_cta_text": "Get Your Quote Now", "variant_b_theme_color": "#10b981" }'
PATCH /api/v1/ab-tests?id={ab_test_id}
Pause, resume, or adjust traffic split for a running test.
FieldTypeDescription
statusstringrunning or paused
traffic_weight_bintegerAdjusted traffic percentage for Variant B
POST /api/v1/ab-tests/promote
Promote the winning variant to become the canonical widget for the site. Closes the test.
FieldTypeDescription
ab_test_id requiredstringTest to close
winner_widget_id requiredstringWidget ID of the winning variant
GET /api/v1/ab-tests/resolve?api_key=sb_pub_...
Resolve A/B test assignment inputs for the widget loader. Called automatically on each page load. When a running test applies, the response includes both publishable keys and the B traffic weight so the client can assign the visitor locally. If no running test applies, the response returns variant: null and echoes the original publishable key. Public endpoint — uses a publishable key only.
Active test response
{ "error": false, "success": true, "data": { "ab_test_id": "abt_xxxxx", "api_key_a": "sb_pub_variant_a", "api_key_b": "sb_pub_variant_b", "weight_b": 50, "widget_a_id": "wgt_variant_a", "widget_b_id": "wgt_variant_b" } }
No running test response
{ "error": false, "success": true, "data": { "variant": null, "api_key": "sb_pub_xxxxx" } }

Widget Public Endpoints

These endpoints are called directly by the <salesbooth-deal> widget using a publishable API key (sb_pub_*). They can also be called from custom storefront code to build headless checkout flows, including holding and confirming booking slots for bookable products.

GET /api/v1/widget-intelligence
Returns aggregated, privacy-safe product intelligence for the widget: popularity badges, most-chosen option defaults, deal price distribution, and win-probability context. Used to pre-select options and display social proof without exposing individual transaction data. Authenticate with a publishable key passed as Authorization: Bearer sb_pub_..., X-API-Key: sb_pub_..., or ?api_key=sb_pub_....
ParameterTypeDescription
api_keyquery stringOptional publishable key for callers that cannot send custom headers. Prefer Authorization: Bearer sb_pub_... or X-API-Key: sb_pub_... when possible.
productsstringComma-separated product IDs to analyse (falls back to widget config)
Example
curl "https://api.salesbooth.com/v1/widget-intelligence?products=prod_aaa,prod_bbb" \ -H "Authorization: Bearer sb_pub_xxxxx"
Response
{ "error": false, "success": true, "data": { "products": { "prod_aaa": { "rank": 1, "badge": "most_popular", "closed_deal_count": 142 }, "prod_bbb": { "rank": 2, "badge": null, "closed_deal_count": 87 } }, "option_defaults": { "prod_aaa": { "tier": { "value": "pro", "selection_rate": 68, "should_preselect": true } } }, "price_context": { "avg_deal_value": 420.00, "min_deal_value": 99.00, "max_deal_value": 999.00 } } }
POST /api/v1/widget-contract?action=generate
Generate contract HTML from a template during the widget checkout flow. The rendered HTML is shown to the buyer before they digitally sign. Authenticated with a publishable key.
FieldTypeDescription
api_keystringPublishable key (sb_pub_*). Required for authentication; may be sent in this body field, Authorization: Bearer, or X-API-Key.
deal_id requiredstringDeal to generate contract for
customer_namestringBuyer name for template personalisation
customer_emailstringBuyer email for template personalisation
POST /api/v1/widget-contract?action=sign
Record a digital signature on a generated contract. Accepts typed name, checkbox acceptance, or drawn signature (base64 PNG).
FieldTypeDescription
contract_id requiredstringContract from the generate response
deal_id requiredstringAssociated deal
signer_namestringFull legal name of the signer. Required when signature_mode is type.
signer_emailstringOptional signer’s email address
signature_modestringcheckbox, type, draw, or digital
signature_imagestringBase64 PNG data URI for drawn signatures
POST /api/v1/widget-discount
Validate a promo code during widget checkout and return the discount to apply. Rate-limited to 10 attempts per minute per IP to prevent code enumeration. Authenticate with a publishable key passed as Authorization: Bearer sb_pub_..., X-API-Key: sb_pub_..., or ?api_key=sb_pub_....
FieldTypeDescription
api_keyquery stringOptional publishable key for browser callers that cannot send custom headers
code requiredstringPromo code entered by the buyer
subtotal requirednumberCart subtotal to calculate the discount amount against
currencystringOptional ISO 4217 effective checkout currency override. Send the buyer/widget currency for multi-currency sessions so fixed-amount promo validation and rounding use the active checkout currency.
Example
curl -X POST https://api.salesbooth.com/v1/widget-discount \ -H "Authorization: Bearer sb_pub_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "code": "SAVE20", "subtotal": 450.00, "currency": "USD" }'
Response
{ "error": false, "success": true, "data": { "valid": true, "discount": { "type": "percentage", "value": 20, "code": "SAVE20", "description": "20% off your first purchase", "amount": 90.00, "min_subtotal": 0 } } }
GET /api/v1/widget-negotiations?deal_id={deal_id}
Load buyer-safe negotiation history for a widget-owned negotiation deal. Authenticate with a publishable key passed as Authorization: Bearer sb_pub_..., X-API-Key: sb_pub_..., or ?api_key=sb_pub_.... The response returns sanitized rounds only, so embedded widget callers can read negotiation state without exposing private seller identifiers.
FieldTypeDescription
deal_id requiredquery stringWidget-owned deal ID to load negotiation history for
api_keyquery stringOptional publishable key for browser callers that cannot send custom headers
Example
curl "https://api.salesbooth.com/v1/widget-negotiations?deal_id=deal_xxxxx&api_key=sb_pub_xxxxx"
Response
{ "error": false, "success": true, "data": { "deal_id": "deal_xxxxx", "rounds": [ { "negotiation_id": "nego_xxxxx", "deal_id": "deal_xxxxx", "round_number": 1, "proposer_type": "agent", "proposed_terms": { "pricing_model": "fixed", "payment_terms": "due_on_receipt", "custom_terms": { "proposed_total": 900, "original_total": 1000, "currency": "USD" } }, "message": "Buyer proposal", "status": "proposed", "expires_at": "2026-03-20T18:00:00Z", "created_at": "2026-03-18T11:24:00Z" } ], "total_rounds": 1 } }
POST /api/v1/widget-negotiations?deal_id={deal_id}&action={action}
Create or respond to buyer-facing widget negotiations for a widget-owned deal. Authenticate with a publishable key passed as Authorization: Bearer sb_pub_..., X-API-Key: sb_pub_..., or ?api_key=sb_pub_.... Use propose and counter with structured proposed_terms, accept to accept the latest seller round, or reject to decline it with an optional reason.
FieldTypeDescription
deal_id requiredquery stringWidget-owned deal ID to mutate
action requiredstringMust be propose, counter, accept, or reject
proposed_termsobjectRequired for propose and counter. Structured deal terms such as pricing model, payment terms, and custom totals to negotiate.
messagestringOptional buyer message for propose or counter
expires_atstringOptional ISO 8601 expiry timestamp for propose or counter
reasonstringOptional buyer-provided rejection reason for reject
Example: action=propose
curl -X POST "https://api.salesbooth.com/v1/widget-negotiations?deal_id=deal_xxxxx&action=propose" \ -H "Authorization: Bearer sb_pub_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "proposed_terms": { "pricing_model": "fixed", "payment_terms": "due_on_receipt", "custom_terms": { "proposed_total": 900, "original_total": 1000, "currency": "USD" } }, "message": "Could you do 900 if we sign today?", "expires_at": "2026-03-20T18:00:00Z" }'
Example: action=counter
{ "proposed_terms": { "pricing_model": "fixed", "payment_terms": "due_on_receipt", "custom_terms": { "proposed_total": 950, "original_total": 1000, "currency": "USD" } }, "message": "I can agree at 950.", "expires_at": "2026-03-21T18:00:00Z" }
Example: action=accept
{}
Example: action=reject
{ "reason": "This is outside our budget for this quarter." }
Response
{ "error": false, "success": true, "data": { "negotiation_id": "nego_xxxxx", "deal_id": "deal_xxxxx", "round_number": 2, "proposer_type": "agent", "proposed_terms": { "pricing_model": "fixed", "payment_terms": "due_on_receipt", "custom_terms": { "proposed_total": 900, "original_total": 1000, "currency": "USD" } }, "message": "Could you do 900 if we sign today?", "status": "proposed", "expires_at": "2026-03-20T18:00:00Z", "created_at": "2026-03-18T11:24:00Z" } }
POST /api/v1/widget-bookings
Hold a booking slot for widget checkout. Authenticate with a publishable key passed as Authorization: Bearer sb_pub_..., X-API-Key: sb_pub_..., or ?api_key=sb_pub_.... The booking is created in held status and expires automatically if it is not confirmed.
FieldTypeDescription
product_id requiredstringBookable product to reserve a slot for
staff_id requiredstringStaff member assigned to the held slot
date requiredstringBooking date in YYYY-MM-DD format
start_time requiredstringSlot start time in HH:MM or HH:MM:SS format
durationintegerSlot length in minutes. Defaults to 60; allowed range is 5 to 480
customer_namestringBuyer name attached to the held booking
customer_emailstringBuyer email address
customer_phonestringBuyer phone number
notesstringOptional booking notes stored with the hold
Example
curl -X POST https://api.salesbooth.com/v1/widget-bookings \ -H "Authorization: Bearer sb_pub_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "product_id": "prod_service", "staff_id": "stf_12345", "date": "", "start_time": "14:30", "duration": 60, "customer_name": "Alex Buyer", "customer_email": "alex@example.com" }'
Response
{ "error": false, "success": true, "data": { "booking": { "booking_id": "bkng_xxxxx", "status": "held", "product_id": "prod_service", "staff_id": "stf_12345", "booking_date": "", "start_time": "14:30:00" } } }
PATCH /api/v1/widget-bookings?id={booking_id}
Confirm a held booking after deal creation. Authenticate with a publishable key passed as Authorization: Bearer sb_pub_..., X-API-Key: sb_pub_..., or ?api_key=sb_pub_.... The response returns the updated booking in data.booking.
FieldTypeDescription
id requiredquery stringBooking ID to confirm
action requiredstringMust be confirm
deal_id requiredstringDeal created from the held checkout session
line_item_idstringOptional line item to associate with the confirmed booking
customer_idstringOptional existing customer record to attach
confirmation_modestringauto (default) or manual
Example
curl -X PATCH "https://api.salesbooth.com/v1/widget-bookings?id=bkng_xxxxx" \ -H "Authorization: Bearer sb_pub_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "action": "confirm", "deal_id": "deal_xxxxx", "line_item_id": "item_xxxxx", "customer_id": "cust_xxxxx", "confirmation_mode": "auto" }'
Response
{ "error": false, "success": true, "data": { "booking": { "booking_id": "bkng_xxxxx", "status": "confirmed", "deal_id": "deal_xxxxx", "customer_id": "cust_xxxxx" } } }
GET /api/v1/widget-validate?action=rules&product_id={product_id}
Fetches the compatibility and bundle rules a public widget embed needs to enforce product configuration guardrails without requiring products:read. Authenticate with a publishable key passed as Authorization: Bearer sb_pub_..., X-API-Key: sb_pub_..., or ?api_key=sb_pub_....
FieldTypeDescription
action requiredstringMust be rules
product_id requiredquery stringProduct ID to fetch compatibility and bundle rules for
api_keyquery stringOptional publishable key for browser callers that cannot send custom headers
Example
curl "https://api.salesbooth.com/v1/widget-validate?action=rules&product_id=prod_aaa&api_key=sb_pub_xxxxx"
Response
{ "error": false, "success": true, "data": { "product_id": "prod_aaa", "compatibility_rules": [ { "rule_id": "rule_123", "source_option_id": "opt_pro", "target_option_id": "opt_support", "rule_type": "requires", "message": "Pro requires Support", "is_active": true } ], "bundle_rules": [ { "bundle_id": "bundle_456", "name": "Pro Bundle", "discount_type": "fixed", "discount_value": 25, "min_options": 2, "is_active": true, "option_ids": ["opt_pro", "opt_support"] } ] } }
POST /api/v1/widget-validate
Validates a product configuration for a headless widget session. Checks compatibility rules (requires / excludes) and returns any price adjustments from includes_price rules. Use checkbox_values to scope checkbox-group required/min/max validation by option key when groups can share the same choice value. Call this before creating a deal to surface configuration errors early. Authenticate with a publishable key passed as Authorization: Bearer sb_pub_..., X-API-Key: sb_pub_..., or ?api_key=sb_pub_....
FieldTypeDescription
api_keyquery stringOptional publishable key for browser callers that cannot send custom headers
product_id requiredstringProduct to validate the configuration for
option_idsstring[]Array of selected option IDs to validate against compatibility rules
text_valuesobjectOptional map of text option keys to buyer-entered values for required, max length, and pattern validation
checkbox_valuesobjectOptional map of checkbox-group option keys to selected choice values. Use this when checkbox groups can share the same choice value so required/min/max validation is scoped correctly per group.
Example
curl -X POST https://api.salesbooth.com/v1/widget-validate \ -H "Authorization: Bearer sb_pub_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "product_id": "prod_aaa", "option_ids": ["opt_pro", "yes"], "text_values": { "engraving": "For Alex" }, "checkbox_values": { "support_options": ["yes"] } }'
Response
{ "error": false, "success": true, "data": { "valid": true, "errors": [], "warnings": [], "price_adjustments": [ { "rule_id": 12, "option_id": "opt_annual", "adjusted_price": 0.00, "reason": "Price included with option opt_pro" } ] } }
POST /api/v1/widget-payment-preview
Previews the full payment breakdown for a headless widget cart: subtotal, option modifiers, promo code discount, tax, total, and the actual charge amount (which may be a deposit rather than the full total depending on the widget configuration). Use this to display an accurate payment summary before initiating checkout. Rate-limited to 30 requests per minute per IP. Authenticate with a publishable key passed as Authorization: Bearer sb_pub_..., X-API-Key: sb_pub_..., or ?api_key=sb_pub_....
FieldTypeDescription
api_keyquery stringOptional publishable key for browser callers that cannot send custom headers
itemsarrayMulti-item cart to preview. Use this or the legacy product_id shape. Each item accepts product_id (required), optional option_ids, optional keyed option_selections, and optional quantity (default: 1)
product_idstringLegacy single-item product ID. Required only when items is omitted
option_idsstring[]Legacy single-item selected option IDs — their price modifiers are included in the subtotal
option_selectionsobjectLegacy single-item selected option values keyed by configuration option key. Use this with option_ids when inline option schema context matters
quantityintegerLegacy single-item quantity (default: 1)
promo_codestringLegacy single promo code to factor into the discount calculation
promo_codesstring[]Promo codes to apply in order after bundle discounts
currencystringCurrency override for the preview. Defaults to the widget currency or USD
payment_typestringPayment collection mode override: full, deposit, or quote
deposit_typestringDeposit calculation method override: fixed or percentage
deposit_valuenumber | nullDeposit amount override. Uses a fixed amount or a percentage based on deposit_type
Example
curl -X POST https://api.salesbooth.com/v1/widget-payment-preview \ -H "Authorization: Bearer sb_pub_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "items": [ { "product_id": "prod_aaa", "option_ids": ["opt_pro"], "option_selections": { "plan": "pro" }, "quantity": 1 }, { "product_id": "prod_bbb", "quantity": 2 } ], "promo_codes": ["SAVE20", "BUNDLE10"], "currency": "USD", "payment_type": "deposit", "deposit_type": "percentage", "deposit_value": 25 }'
Response
{ "error": false, "success": true, "data": { "items": [], "subtotal": 450.00, "discount": 90.00, "bundle_discounts": [], "bundle_discount_total": 0, "promo_discount": 90.00, "promo_details": { "code": "SAVE20", "discount_type": "percentage", "discount_value": 20, "discount_amount": 90.00 }, "auto_discount_total": 0, "auto_discounts_applied": [], "compatibility_errors": [], "tax": 29.52, "total": 389.52, "chargeAmount": 97.38, "isDeposit": true, "currency": "USD" } }

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.

GET /api/v1/fx-rate
Return the current exchange rate from one currency to another.
ParameterTypeDescription
from requiredstringSource currency (ISO 4217, e.g. AUD)
to requiredstringTarget 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.

GET /api/v1/schema/state-machine
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.
ParameterTypeDescription
entitystringdeals 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": { "entity_type": "deal", "initial_state": "draft", "states": { "draft": { "terminal": false, "transitions": [ { "target": "in_progress", "conditions": [ { "field": "line_items", "check": "not_empty", "description": "Deal must have at least one line item" } ], "action": { "method": "POST", "endpoint": "/api/v1/deals?id={deal_id}&action=transition&status=in_progress" }, "required_scope": "deals:write" } ] }, "in_progress": { "terminal": false, "transitions": [{ "target": "pending_signature" }, { "target": "pending_payment" }] }, "pending_signature": { "terminal": false, "transitions": [{ "target": "pending_payment" }] }, "awaiting_signatures": { "terminal": false, "transitions": [{ "target": "pending_payment" }] }, "pending_payment": { "terminal": false, "transitions": [{ "target": "closed" }] }, "partially_accepted": { "terminal": false, "transitions": [{ "target": "pending_signature" }, { "target": "closed" }] }, "closed": { "terminal": true, "transitions": [] }, "cancelled": { "terminal": true, "transitions": [] }, "expired": { "terminal": true, "transitions": [] } } } } }
GET /api/v1/schema/deal-terms
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": "https://json-schema.org/draft/2020-12/schema", "$id": "https://salesbooth.com/api/schemas/deal-terms.json", "title": "Deal Terms", "type": "object", "properties": { "terms_schema_version": { "type": "string", "const": "1.0" }, "payment_terms": { "type": "object", "properties": { "type": { "type": "string", "enum": ["upfront", "net_7", "net_14", "net_30", "net_60", "net_90", "milestone", "installment", "upon_delivery", "custom"] }, "due_date": { "type": "string", "format": "date-time" } } }, "delivery": { "type": "object", "properties": { "method": { "type": "string", "enum": ["digital", "physical", "service", "hybrid"] }, "estimated_days": { "type": "integer", "minimum": 0 } } }, "warranty": { "type": "object", "properties": { "duration_days": { "type": "integer", "minimum": 0 } } } }, "additionalProperties": false } }

Object Schemas

Human-readable field definitions for the core resource objects returned by the API.

Deal Object

FieldTypeDescription
idstringUnique identifier, prefix deal_
tenant_idstringTenant that owns the deal
customer_idstringAssociated customer identifier
titlestringHuman-readable deal name (max 255 chars)
descriptionstringOptional deal description
statusenumdraft · in_progress · pending_signature · awaiting_signatures · pending_payment · partially_accepted · closed · cancelled · expired
deal_typeenumone_time or recurring
currencystringISO 4217 currency code (e.g. USD)
tax_ratedecimalTax rate (stored as 0.1000 for 10%)
subtotaldecimalSum of line items before tax — calculated, read-only
totaldecimalSubtotal + tax — calculated, read-only
line_itemsarrayArray of line item objects (see below)
metadataobjectArbitrary key-value pairs (max depth 3)
versionintegerOptimistic lock version; pass in If-Match on PATCH
created_atISO 8601Creation timestamp
updated_atISO 8601Last modification timestamp
Line Item Object
{ "item_id": "item_xxxxx", "deal_id": "deal_xxxxx", "product_id": "prod_xxxxx", "quantity": 2, "unit_price": "499.00", "subtotal": "998.00" }

Customer Object

FieldTypeDescription
idstringUnique identifier, prefix cust_
namestringFull name (encrypted at rest)
emailstringEmail address (encrypted at rest)
phonestringPhone number (encrypted at rest, optional)
companystringCompany or organisation name
metadataobjectArbitrary key-value pairs
created_atISO 8601Creation timestamp
updated_atISO 8601Last modification timestamp

Product Object

FieldTypeDescription
idstringUnique identifier, prefix prod_
namestringProduct display name
descriptionstringProduct description
pricedecimalBase price (subject to configured pricing rules)
typeenumproduct · service · subscription · bundle
statusenumactive · inactive · archived
skustringOptional stock-keeping unit identifier
currencystringISO 4217 currency for this product’s base price
metadataobjectArbitrary key-value pairs
created_atISO 8601Creation timestamp

Health Check

Public endpoint for monitoring and infrastructure probes. No authentication required. Rate limited to 10 requests per minute per IP.

GET /api/v1/health
Full health report including database, cache, and queue status. Default requests return HTTP 503 when critical dependencies are unhealthy, and ?type=readiness returns HTTP 503 under the same conditions, using the same flat health payload. Use ?type=liveness for an explicit always-200 upstream probe.
ParameterDescription
typeliveness — 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", "timestamp": "2026-03-18T10:00:00Z", "checks": { "database": { "status": "healthy" }, "redis": { "status": "healthy" }, "cache": { "status": "healthy", "backends": { "apcu": true, "redis": true } }, "api": { "status": "healthy", "requests_5m": 42, "error_rate_5m": 0, "avg_response_ms": 118 }, "circuit_breakers": { "status": "healthy", "services": { "stripe": "closed", "twilio": "closed", "email": "closed", "mcp_tools": "closed", "geolocation": "closed" }, "details": { "stripe": { "state": "closed", "failure_count": 0, "consecutive_successes": 0, "backoff_multiplier": 1, "last_failure_at": null, "opened_at": null, "closed_at": "2026-03-18 09:58:00" } } }, "job_queue": { "status": "healthy", "total_pending": 0, "by_topic": {}, "redis_queue_depths": {}, "redis_total_pending": 0 }, "disk": { "status": "healthy", "used_percent": 41.2, "free_mb": 15236 } } }
Response (503, default or ?type=readiness)
{ "status": "unhealthy", "timestamp": "2026-03-18T10:00:00Z", "checks": { "database": { "status": "unhealthy", "message": "Connection failed" }, "redis": { "status": "healthy" }, "cache": { "status": "degraded", "backends": { "apcu": true } }, "api": { "status": "degraded", "requests_5m": 312, "error_rate_5m": 18.27, "avg_response_ms": 842 }, "circuit_breakers": { "status": "degraded", "services": { "stripe": "open", "twilio": "closed", "email": "closed", "mcp_tools": "half_open", "geolocation": "closed" }, "details": { "stripe": { "state": "open", "failure_count": 5, "consecutive_successes": 0, "backoff_multiplier": 4, "last_failure_at": "2026-03-18 09:59:12", "opened_at": "2026-03-18 09:59:12", "closed_at": null } } }, "job_queue": { "status": "degraded", "total_pending": 12458, "by_topic": { "emails": { "pending": 12458, "processing": 2 } }, "redis_queue_depths": { "emails": 12458 }, "redis_total_pending": 12458 }, "disk": { "status": "warning", "used_percent": 96.1, "free_mb": 412 } } }

Deal Participants

Manage multi-party deal collaboration. Participants are agents or humans invited to a deal with specific roles, optional scope details, line-item assignments, and revenue-share allocations. Supported roles: primary, subcontractor, reviewer, observer, required_signer.

GET /api/v1/deal-participants?deal_id={id}
List all participants for a deal. Use action=settlements to retrieve final revenue-share settlement records.
ParameterDescription
deal_id requiredDeal identifier
actionsettlements — return settlement records for a completed deal
POST /api/v1/deal-participants?deal_id={id}
Invite a participant, or perform lifecycle actions (accept, complete). Send X-Delegation-ID header if acting on behalf of an agent.
FieldTypeDescription
agent_api_key_id requiredintegerAPI key record ID for the agent being invited
role requiredstringprimary, subcontractor, reviewer, observer, or required_signer
revenue_share_percentnumberRevenue share percentage (0–100)
revenue_share_fixednumberFixed revenue-share amount in deal currency
scope_descriptionstringOptional description of the participant’s delegated scope
line_item_idsstring[]Optional list of line item IDs assigned to this participant
delegation_idstringOptional delegation record associated with this invitation
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_api_key_id": 123, "role": "subcontractor", "revenue_share_percent": 25, "scope_description": "May negotiate this deal", "line_item_ids": ["item_abc"] }'
PATCH /api/v1/deal-participants?id={participant_id}
Update a participant’s role, scope, or revenue-share allocation.
DELETE /api/v1/deal-participants?id={participant_id}
Remove (withdraw) a participant from a deal. Only possible while the deal is in draft or in_progress status.

Payment Intent

Create a payment intent 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.

POST /api/v1/payment-intent
Create a payment intent. Returns a client_secret for use with the payment form to complete payment on the client.

This endpoint supports the optional Idempotency-Key header. Reuse the same key when retrying the same payment-intent creation request after a timeout or lost response.

FieldTypeDescription
deal_id requiredstringDeal to create a PaymentIntent for
amountnumberOptional expected charge amount in the deal currency. If provided, it must match the server-authoritative remaining required deposit or remaining full deal total; mismatches return 409 pricing_mismatch.
Response (201)
{ "error": false, "success": true, "data": { "client_secret": "pi_xxx_secret_yyy", "payment_intent_id": "pi_xxx", "amount": 1499.00, "currency": "usd" } }

Changelog

The public changelog is pending publication. Until entries are backfilled, use the API, SDK, and widget version notes above as the source of truth for current developer-facing changes.

© 2026 Salesbooth. OpenAPI Spec