Tough Customer workspace API
Every tool the MCP connector exposes, callable over plain HTTPS with a workspace API key — for scripts, back-office jobs and partners that cannot run an OAuth flow.
Authentication
A workspace admin mints an API key under Integrations → REST API. The key is shown exactly once (only its hash is stored). Send it on every request as a bearer token:
Authorization: Bearer tc_…
A key acts as the admin who minted it — including their Salesforce connection — and reaches exactly the tools that admin sees. If that admin is demoted to member, the key keeps working for member tools only; if they leave the workspace, the key is revoked automatically. Keys belong to one workspace: the {orgId} in the URL must be that workspace's id (the same id as the workspace's MCP URL, shown next to the endpoint on the keys page). Never put a key in a URL — it is refused there, and URLs get logged along the way. Rotate by minting a new key and revoking the old one.
Endpoints
Two routes, both under your workspace's endpoint:
GET https://app.toughcustomer.ai/api/v1/{orgId}/tools # the catalog this key may call
POST https://app.toughcustomer.ai/api/v1/{orgId}/tools/{tool} # run one tool; the JSON body is its argumentsList your scenarios:
curl -s -X POST https://app.toughcustomer.ai/api/v1/{orgId}/tools/list_scenarios \
-H "Authorization: Bearer tc_…" \
-H "Content-Type: application/json" \
-d '{}'A successful call returns the tool's output decoded as JSON:
{ "ok": true, "tool": "list_scenarios", "result": [ { "id": 42, "name": "Pricing objection", "category": "Roleplay" } ] }Arguments are validated against the tool's schema before it runs — the same JSON schema MCP clients see in tools/list, and the same schema the catalog returns as inputSchema. Tools without required arguments accept an empty body. Bodies are limited to 2 MiB and must be application/json. Every response is Cache-Control: no-store and carries an X-Request-Id to quote to support.
Errors
Every error is one JSON envelope:
{ "ok": false, "error": "<code>", "message": "…" }| error | HTTP | Meaning |
|---|---|---|
unauthorized | 401 | Missing, malformed, unknown, revoked or expired key — or the key's owner left the workspace. |
not_found | 404 | The key does not belong to the workspace in the URL, the workspace id is unknown, or the tool does not exist (one constant body for all three). |
forbidden | 403 | An admin-only tool called with a key whose owner is not (or no longer) a workspace admin. |
conflict | 409 | The tool reports a conflict (for example a duplicate). |
invalid_json | 400 | The body is not a JSON object. |
invalid_arguments | 400 | The body does not match the tool's schema — issues[] lists each violation with its path. |
unsupported_media_type | 415 | A body without Content-Type: application/json. |
payload_too_large | 413 | The body is over 2 MiB. |
tool_error | 422 | The tool refused the call; message is the tool's own text (for example a session id from another workspace). |
rate_limited | 429 | The key's per-minute limit is exceeded — see Rate limits. |
internal | 500 | An unexpected failure; message carries a reference id for support. |
A 401 carries WWW-Authenticate: Bearer. A 404 is deliberately the same body whether the workspace id, the key's workspace or the tool name is wrong.
Rate limits
Each key may make 60 calls per minute (catalog reads and tool calls alike), counted in a fixed calendar-minute window. Every authenticated response carries X-RateLimit-Limit and X-RateLimit-Remaining; over the limit you get 429 rate_limited with Retry-After (seconds) and retryAfterSeconds in the body. Calls resume in the next minute. Need more? Ask support@toughcustomer.ai.
Tools
Every key reaches the member tools; behavior labels come from the same certification the server publishes to MCP clients as tool annotations. Salesforce-backed tools run on the key owner's Salesforce connection.
| Tool | Call | Behavior | What it does |
|---|---|---|---|
List AI-buyer simulations list_simulations | POST …/tools/list_simulations | read-only | List the org's saved AI-buyer simulations. |
Create AI buyer from URL create_simulation | POST …/tools/create_simulation | write | Generate a new AI buyer persona from a company URL. |
Start roleplay session create_roleplay_session | POST …/tools/create_roleplay_session | write | Start a voice roleplay session for a scenario. |
Get session score get_session_score | POST …/tools/get_session_score | read-only | Fetch the score + coaching for a completed roleplay session. |
List scenarios list_scenarios | POST …/tools/list_scenarios | read-only | List the org's practice scenarios. |
List AI voices list_voices | POST …/tools/list_voices | read-only | List the available AI-buyer voices. |
My assigned learning tough_learning | POST …/tools/tough_learning | read-only | Open the learning dashboard — assigned journeys + progress. |
Connect Salesforce connect_salesforce | POST …/tools/connect_salesforce | read-only | Authorize Salesforce for your user (per-user OAuth). |
Disconnect Salesforce disconnect_salesforce | POST …/tools/disconnect_salesforce | write (destructive) | Revoke your Salesforce authorization. |
List Salesforce opportunities list_opportunities | POST …/tools/list_opportunitiesowner's Salesforce | read-only | List your Salesforce opportunities. |
Get opportunity contacts get_opportunity_contacts | POST …/tools/get_opportunity_contactsowner's Salesforce | read-only | List the contacts on a Salesforce opportunity. |
Get deal-coaching context get_coach_context | POST …/tools/get_coach_contextowner's Salesforce | read-only | Pull deal-coaching context for a Salesforce opportunity. |
Save roleplay scenario create_roleplay | POST …/tools/create_roleplay | write | Save a reusable, team-wide roleplay scenario. |
Admin tools
Available while the key's owner is a workspace admin — analytics export, scenario and rubric authoring, and member invitations. With a demoted owner these answer 403.
| Tool | Call | Behavior | What it does |
|---|---|---|---|
Export session analytics export_session_analytics | POST …/tools/export_session_analytics | read-only | Export org-wide session analytics (rows + summary). |
Analytics HTML report analytics_report_html | POST …/tools/analytics_report_html | read-only | Generate a self-contained HTML analytics dashboard. |
Invite teammate invite_user | POST …/tools/invite_user | write | ADMIN ONLY. Invite a teammate by email with a workspace permission + profile fields (T98). |
Create scenario create_scenario | POST …/tools/create_scenario | write | Create a scenario in any creatable category (full editable field set). |
Get scenario get_scenario | POST …/tools/get_scenario | read-only | Read one scenario's full editable fields by id. |
Update scenario update_scenario | POST …/tools/update_scenario | write (destructive) | Partially update a scenario — body, scoring prompt, any editable field. |
Delete scenario delete_scenario | POST …/tools/delete_scenario | write (destructive) | Delete a scenario from the org catalog (confirm required). |
Create competencies create_competencies | POST …/tools/create_competencies | write | Bulk-insert a competency record set under one category (deduped). |
Update competencies update_competencies | POST …/tools/update_competencies | write (destructive) | Edit/add/delete competencies in one category + subcategory group. |
List competencies list_competencies | POST …/tools/list_competencies | read-only | The org rubric grouped category → subcategory → items. |
Workspace custom tools
Custom tools authored under Integrations → Custom tools (Salesforce GraphQL, HTTP APIs, Claude agents) are per-workspace, so they are not in the OpenAPI document: read them from your workspace's catalog (GET …/tools, entries with kind: "workspace") and call them by name exactly like a built-in tool.
OpenAPI
The machine-readable specification is generated from the same tool definitions as this page and the MCP server, so it cannot drift from the live API:
https://app.toughcustomer.ai/api/v1/openapi.json
OpenAPI 3.1, bearer security scheme, one operation per built-in tool with its request schema, and the error envelope above. Import it into Postman, Bruno, Swagger UI or your code generator; the document is public and CORS-open. An in-page API explorer is coming with the user-registration endpoint.
Data handling
Calls read and write only the key's workspace, attributed to the key's owner and to the key itself in the workspace's usage ledger. Unexpected errors return a reference id instead of internal details. See the Privacy Policy for what we store and how AI providers process session content, and the Terms of Service for acceptable use. Prefer an OAuth sign-in for a person's own use? That is the MCP connector.