API & MCP Access
API & MCP Access
Section titled “API & MCP Access”Aptiwise lets you submit workflows from scripts, integrations, and AI assistants — using the same access rules that apply in the app. A personal API token (ffat_...) is the credential for both surfaces.
Step 1 — Generate a token
Section titled “Step 1 — Generate a token”- Open your Profile page (top-right menu → Profile).
- Scroll to the API & MCP Access section.
- Click New Token, give it a name (e.g.
Claude DesktoporMy Script), and click Create. - Copy the token — you can retrieve it again at any time from the same section.
Access control: A token grants no more access than your normal user account. Each workflow submission is checked against that workflow’s submission criteria, just like the UI.
Step 2a — Submit via REST API
Section titled “Step 2a — Submit via REST API”Find the workflow UUID
Section titled “Find the workflow UUID”The workflow UUID appears in the URL when you open a workflow in the admin panel. You can also list all workflows you are eligible to submit using your API token:
curl https://app.aptiwise.com/services/v1/api-tokens/external/workflows \ -H "Authorization: Bearer ffat_..."Response:
[ { "uuid": "abc123-...", "name": "Expense Report", "description": "Submit expense claims" }, { "uuid": "def456-...", "name": "Leave Request", "description": null }]Submit a workflow
Section titled “Submit a workflow”curl -X POST https://app.aptiwise.com/services/v1/api-tokens/external/workflows/{workflow_uuid}/submit \ -H "Authorization: Bearer ffat_..." \ -H "Content-Type: application/json" \ -d '{ "fields": { "amount": 1500, "reason": "Team offsite catering", "expense_date": "2026-05-25" } }'Response:
{ "instance_uuid": "a1b2c3d4-...", "status": "in_progress", "workflow_name": "Expense Report"}The fields keys must match the field names defined in the workflow form. Required fields must be included or the submission will be rejected.
Error codes
Section titled “Error codes”| Code | Meaning |
|---|---|
401 |
Token missing, invalid, or revoked |
403 |
Your employee profile doesn’t satisfy the workflow’s submission criteria |
404 |
Workflow UUID not found or the workflow is inactive |
422 |
Required form fields are missing — the error detail lists the field labels |
List registered assets
Section titled “List registered assets”Use GET /api-tokens/external/assets to retrieve assets you have view access to. This is useful for building iteration lists in scheduled workflows — for example, fetching all registered server baselines before spawning one drift-check workflow per server.
curl "https://app.aptiwise.com/services/v1/api-tokens/external/assets" \ -H "Authorization: Bearer ffat_..."Filter by category or name prefix
Section titled “Filter by category or name prefix”# All DigitalOcean assets whose name starts with "DO-"curl "https://app.aptiwise.com/services/v1/api-tokens/external/assets?category=DigitalOcean&name_prefix=DO-" \ -H "Authorization: Bearer ffat_..."Query parameters:
| Param | Type | Description |
|---|---|---|
category |
string | Exact match on the asset’s category (e.g. DigitalOcean, AWS) |
name_prefix |
string | SQL LIKE prefix match on the asset name (e.g. DO- matches DO-12345) |
Response:
[ { "uuid": "550e8400-...", "name": "DO-87654321", "category": "DigitalOcean", "updated_at": "2026-05-30T14:22:00Z" }]Note:
propertiesis intentionally omitted from this response — it may contain SSH keys, API credentials, or other sensitive configuration. Workflows that need the full properties load them internally via anasset: data_tostep (see Asset Registry & Data Steps).
Access rules
Section titled “Access rules”You only see assets where your company_roles intersect with the asset’s view_roles. If an asset has no view_roles configured it is visible to all authenticated token holders in the company.
Step 2b — Connect an AI assistant via MCP
Section titled “Step 2b — Connect an AI assistant via MCP”The Model Context Protocol lets AI assistants like Claude Desktop, Cursor, or Windsurf discover and submit workflows on your behalf.
Get your MCP config snippet
Section titled “Get your MCP config snippet”In the API & MCP Access section of your Profile page, expand How to install on an AI platform. Select your token and copy the config snippet — it looks like this:
{ "my-script": { "type": "streamable-http", "url": "https://app.aptiwise.com/services/v1/mcp", "headers": { "Authorization": "Bearer ffat_..." } }}The JSON key (e.g. my-script) is derived from your token’s name and is how the AI assistant labels this server in its sidebar.
Claude Desktop setup
Section titled “Claude Desktop setup”- Open Claude Desktop → Settings → Developer → Edit Config.
- Paste the snippet into the
mcpServersobject. - Restart Claude Desktop.
The assistant will now list all workflows you are eligible to submit as callable tools.
What the AI assistant can do
Section titled “What the AI assistant can do”Once connected, the AI assistant sees one tool per workflow you have access to (e.g. submit_expense_report). It can:
- Ask you to describe what you need
- Fill in the form fields automatically
- Submit the workflow and return the instance ID
The profile page also shows the exact tool name and a sample prompt for each workflow — expand the setup guide and select the workflow from the dropdown to see them.
Revoking a token
Section titled “Revoking a token”To revoke a token, go to Profile → API & MCP Access and click the trash icon next to the token. Any API calls or AI assistant connections using that token will immediately fail with 401.
For admins: connecting an external system (service clients)
Section titled “For admins: connecting an external system (service clients)”Everything above uses a personal token — one credential, always acting as you. If a trusted external system (e.g. an Odoo instance) needs to trigger workflows on behalf of whichever of its own users is currently logged in, a personal token is the wrong fit: you’d have to share one token for everyone, or generate and store one per user in the external system.
A service client solves this instead: one long-lived secret, held only by the external system, exchanged on demand for short-lived (10-minute) tokens that assert a specific user. No per-user secret is ever stored on the external system’s side.
Step 1 — Create a service client
Section titled “Step 1 — Create a service client”- Go to Admin → API Access and scroll to the Service Clients section (company admin only).
- Click New Service Client, name it after the system connecting (e.g.
Odoo Production). - Copy the
client_idandclient_secretshown — the secret is shown exactly once and is not recoverable afterward. Store both in the external system’s own configuration (e.g.odoo.conf), not in a script or a shared doc.
Step 2 — Exchange the secret for a user token
Section titled “Step 2 — Exchange the secret for a user token”The external system calls this itself, server-to-server, immediately before triggering a workflow — not something an end user does by hand:
curl -X POST https://app.aptiwise.com/services/v1/oauth/token \ -u "client_id:client_secret" \ -d grant_type=urn:ietf:params:oauth:grant-type:token-exchange \ -d subject_token=jane@company.com \ -d scope=workflow:triggersubject_token is the email of the user the external system currently has logged in — it must already be an active Aptiwise user in the same company as the service client, or the exchange is rejected.
Response:
{ "access_token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "Bearer", "expires_in": 600, "scope": "workflow:trigger"}Step 3 — Submit a workflow with the exchanged token
Section titled “Step 3 — Submit a workflow with the exchanged token”Use access_token exactly like a personal token at the same submit endpoint:
curl -X POST https://app.aptiwise.com/services/v1/api-tokens/external/workflows/{workflow_uuid}/submit \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \ -H "Content-Type: application/json" \ -d '{ "fields": { "po_number": "PO-4471", "vendor_name": "Acme Supplies", "amount": 500 } }'The resulting instance is attributed to the real user (jane@company.com), not the service client — the audit trail records both.
Getting a PDF back in the same response
Section titled “Getting a PDF back in the same response”If the workflow’s end step sets return_pdf: true (see the ApprovalML syntax reference) and the workflow reaches that step synchronously — i.e. it’s built from automatic/asset/conditional_split steps with no decision, parallel_approval, or wait_webhook step pausing it for a human — the same submit response includes the rendered PDF, base64-encoded, so no second request or download link is needed:
{ "instance_uuid": "a1b2c3d4-...", "status": "approved", "workflow_name": "Odoo PO Approval Certificate", "pdf_base64": "JVBERi0xLjcKJc..."}Decode pdf_base64 and store or attach it however the caller needs — for an Odoo Server Action, that typically means creating an ir.attachment on the triggering record, so the end user never visits Aptiwise or sees any Aptiwise link at all.
If the workflow instead pauses on a human step, pdf_base64 is simply null — there’s no document to return yet.
If the workflow has data_processor/data_source automatic steps, they must set execute_async: false. By default those steps dispatch their fetch to a background worker on first reach and stay PENDING — so the submit response comes back with status: "in_progress" and no PDF, even if the workflow would otherwise complete synchronously. Ask whoever owns the workflow to add execute_async: false to every data_processor/data_source step upstream of the return_pdf end step (see ApprovalML syntax reference) so the fetch runs inline instead. This only makes sense for fetches that finish in well under the HTTP request timeout — if a workflow does genuinely slow lookups before its PDF step, don’t force it synchronous; poll the instance instead.
Error codes (token exchange)
Section titled “Error codes (token exchange)”| Code | Meaning |
|---|---|
401 invalid_client |
Unknown client_id, wrong client_secret, or the service client has been revoked |
400 invalid_target |
subject_token’s email has no active employee record in the service client’s company |
400 invalid_scope |
Requested scope is not one the service client is allowed to grant |
Revoking a service client
Section titled “Revoking a service client”Go to Admin → API Access → Service Clients and click the trash icon. This immediately stops the client from exchanging for new tokens; any token it already minted keeps working only until its own 10-minute expiry.
