Skip to main content
Customer actions let your Suppio agent perform work in your system from Discord tickets and forum threads. You define each action and its arguments. Suppio decides when the action matches a customer’s request and sends a signed HTTPS request to your executor. Customer actions are available on every plan. They are separate from caller-defined tools in the Suppio Agent API.

Connect an executor over HTTPS

Publish your executor from a VPS, private server, or managed host and review every network and security requirement.

Set up an executor

  1. Open your agent and select Customer actions.
  2. Enter the HTTPS URL that will receive action requests.
  3. Leave the endpoint off and select Save endpoint.
  4. Copy the signing secret. Suppio only shows it once.
  5. Add signature verification to your executor.
  6. Select Test connection.
  7. Turn on the endpoint when the test succeeds. The endpoint switch saves immediately.
Each agent has one executor URL and signing secret. All actions for that agent are sent to the same URL and identified by action.name.
Rotating the signing secret immediately invalidates the previous secret. Update your executor before running another customer action.

Receive ticket closing notifications

Turn on Ticket closing notifications below Actions to receive a signed ticket.resolved event whenever Suppio resolves a Discord ticket through the support agent, /close, or inactivity handling. This setting reuses the executor URL and signing secret. When it is active, Suppio marks the ticket resolved but leaves the Discord channel in place so your integration can delete, archive, rename, move, or otherwise process it. If Auto-close tickets is still enabled in Actions, the setting remains Pending. Suppio reminds you every minute until you turn auto-close off. The setting activates automatically afterward. A disabled or deleted executor pauses delivery without clearing your requested setting. Suppio sends:
source is agent, manual, or inactivity. reason and actor.user_id can be null. The request uses the same X-Suppio-Timestamp and X-Suppio-Signature headers as customer actions. It also includes X-Suppio-Event-Id, which matches event_id. Return any 2xx response to acknowledge delivery; Suppio ignores the response body. Store event_id before changing the ticket. Suppio retries retryable failures after 1 minute, 5 minutes, 30 minutes, and 2 hours. Network failures, timeouts, HTTP 408, HTTP 429, and 5xx responses are retryable. Other 4xx responses end delivery.
Test connection sends customer_action.test; it does not send ticket.resolved. A successful connection test therefore does not verify your ticket-resolution branch or X-Suppio-Event-Id handling. Run the signed ticket-resolution smoke test in the complete executor example before enabling closing notifications.

Define an action

Select Add action and provide:
  • Tool name: A stable lowercase identifier such as change_customer_plan.
  • Display name: The action name shown in Discord confirmations and status messages.
  • Description: When the agent should choose the action.
  • Additional instructions: Optional rules for choosing the action or filling its arguments.
  • Require confirmation: Whether the requesting Discord user must select Confirm before execution. This is on by default.
  • Enabled: Whether the action is available to the agent. Keep a new action off until its handler is ready and tested.
  • Arguments: The typed values sent to your executor.
The argument editor generates a strict JSON Schema. Every property is required by the schema. Turn on Allow null when a value is optional. If an imported action uses advanced JSON Schema keywords that the visual editor cannot represent, Suppio opens its arguments in raw JSON mode. Edit and save the schema there to preserve keywords such as format, pattern, numeric limits, $defs, $ref, and anyOf. Switching that action to the form editor requires confirmation because the form removes unsupported keywords.

Import actions

Use Import actions to create several action definitions from one JSON document. This is useful when you want an AI coding agent to inspect your application and generate action definitions that match functions your backend already exposes.
  1. Open your agent and select Customer actions.
  2. Select Import actions, to the right of Add action.
  3. Paste the JSON document or select Choose JSON file.
  4. Review every generated action and argument before importing.
  5. Select Import actions.
An import only creates action definitions. It does not configure the executor URL, add handler code to your application, or replace an existing action.
Treat generated actions like production integration code. Review which operations they expose, require confirmation for mutations, and never import a generic action that accepts executable code, arbitrary URLs, SQL, shell commands, or unrestricted operation names.

Import document format

The import document must be JSON with exactly two top-level fields: version and actions.
The top-level fields are: Each action supports only these fields: The complete import document must be 64 KB or smaller. An agent can have at most 10 actions in total, including actions that already exist. Names must be unique within the document and must not conflict with an existing action. Imports are create-only and atomic. If one action is invalid, a name conflicts, or the batch would exceed the agent limit, Suppio rejects the complete import and creates no actions. Remove or edit existing actions separately before importing replacements. Do not include type: "function", strict, an executor URL, a signing secret, or handler source code in an action object. Unknown fields are rejected. The following names are reserved by Suppio and cannot be imported:
  • check_live_status
  • escalate_to_human
  • file_search
  • flag_knowledge_issue
  • forum_resolution
  • mark_resolved
  • rename_ticket
  • resolve_chat
  • resolve_ticket
  • suggest_title

Strict parameter schemas

Every parameters value must use a strict object JSON Schema:
  • The root must have "type": "object" and cannot use anyOf at the root.
  • Every object must define properties, list every property exactly once in required, and set additionalProperties to false.
  • Use type: ["string", "null"] or the corresponding two-value type array when a value is optional. The property still stays in required; the model sends null when no value applies.
  • Every array must define one items schema.
  • Supported value types are object, array, string, number, integer, boolean, and null through a nullable two-value type array.
  • enum must be a non-empty array. If an enum is nullable, include null in the enum as well as in its type.
  • Descriptions should state meaning, format, units, and how the value maps to your application. Do not put secrets or customer data in descriptions.
This example includes nested objects, arrays, enums, and a nullable value:
Supported schema keywords are:
  • Structure: type, properties, required, additionalProperties, and items.
  • Documentation and choices: title, description, and enum.
  • Strings: format, pattern, minLength, and maxLength.
  • Numbers: minimum, maximum, exclusiveMinimum, exclusiveMaximum, and multipleOf.
  • Arrays: minItems and maxItems.
  • Advanced local composition: $defs, local $ref values beginning with #, and nested anyOf.
Supported string formats are date-time, time, date, duration, email, hostname, ipv4, ipv6, and uuid. Other JSON Schema keywords are rejected. Prefer direct types and nullable type arrays over advanced composition unless your action contract requires it.

Ask an AI coding agent to generate the import

Give the AI agent access to the application code that will receive the webhook. It should inspect real service methods, authorization rules, identifier types, enums, validation, and failure cases instead of inventing operations. You can copy this prompt and replace the bracketed values:
After the AI returns JSON:
  1. Confirm that each name maps to one explicit allowlisted handler in your executor.
  2. Confirm that your executor authorizes actor.user_id for the targeted customer or account. A signed request proves that Suppio sent it; it does not grant the actor permission in your system.
  3. Confirm that identifiers and enum values match your application exactly.
  4. Keep requiresConfirmation on for actions with side effects.
  5. Remove any argument that could turn a narrow action into a generic remote-control interface.
  6. Import the document, then test each action in a non-production account before enabling production mutations.
Your executor should dispatch by the exact imported name and reject every unknown name. For example:
The imported schema tells Suppio what arguments to generate. Your executor must still parse, validate, authorize, and safely handle those arguments before changing data.

Execution request

Suppio sends an HTTPS POST with Content-Type: application/json:
The request includes these authentication headers:
  • X-Suppio-Action-Id: The same UUID as action_id.
  • X-Suppio-Timestamp: The request time as Unix seconds.
  • X-Suppio-Signature: v1= followed by the hexadecimal HMAC-SHA256 signature.
Suppio signs the exact raw body with:

Verify signatures

Always verify the raw request body before parsing JSON. Reject timestamps more than five minutes away from your server time.
This helper is only the signature check. Your route must also validate the event envelope, match the header and body action IDs, allowlist the action name, validate its arguments, authorize the Discord actor, and claim the action ID in durable storage before making a change.

Build the complete executor

Start with the runnable Node.js example, including raw-body handling, schema validation, actor authorization, durable SQLite idempotency, structured errors, and safe service configuration.

Return a result

For success, return an HTTP 2xx response with:
For a known failure, also return HTTP 2xx with:
Suppio reads structured executor results only from 2xx responses. For any 4xx or 5xx response, Suppio discards the response body and reports a generic executor_http_error. Use non-2xx responses for protocol or authentication failures. Use a 2xx response with status: "failed" for an action-level failure that the agent should explain to the user. Suppio sends no more than 64 KB in an action request. Your response can also be up to 64 KB, and summary can be up to 2,000 characters. Executor output is treated as untrusted result data. It is never used as an instruction for the agent to follow.

Timeouts and idempotency

Your executor has 15 seconds to respond. Suppio does not automatically retry customer actions because a retry could repeat a change. Store each action_id before applying a side effect. If you receive the same ID again, return the result of the original execution instead of repeating it. If Suppio loses the connection or reaches the timeout after sending a request, it reports that completion could not be confirmed. The action may still have completed in your system.

Availability, limits, and history

  • The endpoint must be enabled, and the individual action must be enabled, before the action is available to the agent.
  • Suppio can request at most one customer action in one workflow run.
  • A ticket or forum conversation can have only one action awaiting confirmation or executing at a time.
  • One agent can execute up to five customer actions concurrently across conversations.
  • An agent can have up to 15 action definitions.
  • Recent activity shows action runs retained for 30 days.
Saving or toggling the executor endpoint, rotating or deleting its secret, or updating or deleting an action expires every pending confirmation for that agent. The user must request the action again under the new configuration. Creating a separate new action does not expire existing confirmations.

Discord behavior

For actions that require confirmation, Suppio shows the display name and arguments with Confirm and Cancel buttons. Only the user who requested the action can choose. The confirmation expires after 10 minutes. After execution begins, Suppio shows a working message, updates it with the outcome, and sends a separate natural-language reply based on the executor result.