Skip to content

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.


  1. Open your Profile page (top-right menu → Profile).
  2. Scroll to the API & MCP Access section.
  3. Click New Token, give it a name (e.g. Claude Desktop or My Script), and click Create.
  4. 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.


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:

Terminal window
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 }
]
Terminal window
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.

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

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.

Terminal window
curl "https://app.aptiwise.com/services/v1/api-tokens/external/assets" \
-H "Authorization: Bearer ffat_..."
Terminal window
# 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: properties is 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 an asset: data_to step (see Asset Registry & Data Steps).

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.

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.

  1. Open Claude Desktop → Settings → DeveloperEdit Config.
  2. Paste the snippet into the mcpServers object.
  3. Restart Claude Desktop.

The assistant will now list all workflows you are eligible to submit as callable tools.

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.


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.

  1. Go to Admin → API Access and scroll to the Service Clients section (company admin only).
  2. Click New Service Client, name it after the system connecting (e.g. Odoo Production).
  3. Copy the client_id and client_secret shown — 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:

Terminal window
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:trigger

subject_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:

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

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.

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

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.