Saleo Public API
Last updated: September 8, 2026
Demo Personalization workflow
Discover Saleo Live demos, retrieve personalization tokens, and create or maintain personalized views of them programmatically.
Field | Value |
API version | v1 |
Request URL | https://api.platform.saleo.io/ |
Protocol | RPC over JSON; POST-only |
Authentication | Bearer token — a per-user Saleo API key |
1. Overview
The Saleo Public API lets an authorized integration discover Saleo Live demo templates, inspect their text personalization tokens, create personalized views with token overrides, and update those views later — all outside the Saleo Portal.
Support Operations
Endpoint | Description |
| Search demos and personalized views visible to the key's user. |
| List the text tokens of a template or personalized view. |
| Create a personalized view of a template. |
| Update token values and/or rename an owned view. |
2. Authentication
All requests require a bearer token:
Authorization: Bearer <user_api_key>Unlike team-wide tokens, this API uses user API keys. A user API key is bound to the Saleo user who created it: every call acts as that user, sees only the demos they can see, and creates views owned by them.
Creating and managing your key
Any user can create their own key in the Saleo Portal: profile menu → API Keys → Create My API Key. The key value is shown only once, at creation — copy it immediately; it cannot be retrieved later.
Each user can hold one active key at a time. To rotate, revoke the existing key and create a new one.
Revoking a key is permanent and takes effect on its next request. Keys can also be renamed to record what they're used for.
Admins can see and revoke every key on the team under Settings → Manage SCIM/API Access Tokens, including when each was last used. Non-admin users only see their own key.
A key stops working the moment its user is deactivated.
Partner teams: user API keys are not available to Saleo partner (reseller) accounts — neither to create nor to use. This does not apply to standard customer tenants.
Security Recommendation
Call this API from your own backend or approved integration layer, not directly from an untrusted browser client. Store the API key the same way you'd store any credential — encrypted at rest, never embedded in front-end code — and rotate it if it may have been exposed.
3. Quick start: create a personalized demo view
Step 1 — Find a personalizable demo
curl --request POST \
--url https://api.platform.saleo.io/v1/get_live_demos \
--header "Authorization: Bearer $SALEO_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"search": "EA-4711",
"personalizableOnly": true,
"limit": 25
}'
{
"data": [
{
"id": "d3f2a1b0-...",
"name": "EA-4711 ACME Overview",
"tags": ["Retail"],
"owner": { "userId": "u-1", "name": "Sally Seller", "email": "rep@acme.com" },
"personalizable": true,
"personalizedView": false,
"playUrl": "https://.../play/d3f2a1b0-...",
"createdAt": "2026-07-07T12:00:00Z",
"updatedAt": "2026-07-07T12:00:00Z"
}
]
}Step 2 — List the template's tokens
curl --request POST \
--url https://api.platform.saleo.io/v1/get_demo_tokens \
--header "Authorization: Bearer $SALEO_API_KEY" \
--header "Content-Type: application/json" \
--data '{ "demoId": "d3f2a1b0-..." }'
{
"data": [
{ "id": "t-company", "name": "%%company%%", "description": "Customer name",
"tags": ["Company Info"], "value": "ACME", "overridden": false }
]
}Step 3 — Create a personalized view
curl --request POST \
--url https://api.platform.saleo.io/v1/create_personalized_view \
--header "Authorization: Bearer $SALEO_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"demoId": "d3f2a1b0-...",
"name": "ACME for Globex",
"tokenValues": [ { "tokenId": "t-company", "value": "Globex" } ]
}'
{
"view": { "id": "v-0000-...", "name": "ACME for Globex",
"personalizedView": true, "parentDemoId": "d3f2a1b0-...",
"playUrl": "https://.../play/v-0000-..." },
"appliedTokens": [
{ "id": "t-company", "name": "%%company%%", "value": "Globex", "overridden": true }
]
}Every token value in the request must apply. An unknown token id or an over-length value (1000 char max) fails the whole call and creates nothing — there's no partial success to check for.
Step 4 — Update it later
Use the same view id to refresh token values or rename the view as the deal changes — see update_personalized_view below.
4. Endpoint reference
POST /v1/get_live_demos
Returns the demos the key's user works with: personalizable templates they can view, plus their personalized views — the ones they created and any shared with them. Returned newest-created first.
Field | Type | Required | Description |
search | string | No | Case-insensitive match over demo names and tag labels. |
tags | array | No | Tag labels; a demo matches if it carries any of them. |
ownerEmail | string | No | Demos created by this user, matched case-insensitively. |
personalizableOnly | boolean | No | Governs templates only, default true. Personalized views are always returned — filter on personalizedView client-side. |
limit | integer | No | Default 100, capped at 500. |
continuationToken | string | No | Cursor from the previous response. |
POST /v1/get_demo_tokens
Returns the text tokens of a template or a personalized view — tokens declared at any level of the demo's parent chain are included. Image tokens are not returned; this API personalizes text only.
Field | Type | Required | Description |
demoId | string | Yes | A template id or a personalized view id. |
POST /v1/create_personalized_view
Creates a personalized view of a template: a private copy owned by the key's user, carrying the requested token values. Only visible to its creator until shared in the portal.
Field | Type | Required | Description |
demoId | string | Yes | The template to personalize; must be personalizable. |
name | string | Yes | Must be unique within the team. |
tokenValues | array | No | Objects of { tokenId, value }. Values capped at 1000 characters. |
POST /v1/update_personalized_view
Changes token values on a view that already exists, and optionally renames it, so an integration can keep one view id and refresh it as the deal changes. Only the user who created a view can change it.
Field | Type | Required | Description |
viewId | string | Yes | A view owned by this user. |
tokenValues | array | No | Only the tokens named here change; the rest keep their values. |
name | string | No | Rename the view; unique within the team. Re-sending the current name does nothing. |
5. Error format
All error responses share this shape. The HTTP status carries the error class; the body's code field is the corresponding gRPC status number.
{
"code": 5,
"error": "Personalized view not found"
}HTTP status | Meaning |
400 | A required field is missing, a token id is unknown, or a value exceeds 1000 characters — nothing changes. Also covers demo/view-type mismatches, e.g. “This demo does not allow personalized views.” |
401 | Missing API key, an invalid access token, a team-wide token used in place of a user API key, a deactivated user, or a deactivated company account. |
403 | The team is a partner team, or (on update) the view belongs to a different user. |
404 | The demo or view does not exist, or belongs to another team. |
409 | A demo with the requested name already exists. |
6. Integration recommendations
Run Saleo API calls from your own backend service or approved integration layer, not directly from an untrusted browser client.
Map your own business identifiers (transaction, conversation, opportunity, or workflow id) to Saleo demoId and viewId values in a durable integration table.
Cache demo discovery results briefly, but re-read tokens before personalizing when template authors may have changed them.
Validate that a selected demo is personalizable before creating a view.
Treat playUrl as the base launch URL returned by Saleo — append your own ?startUrl= parameter before sharing it, rather than reconstructing the rest of the URL yourself.
Since create and update calls fail atomically, validate token ids and values client-side before sending to avoid unnecessary round trips.