Actions are API calls that users (or automations) can execute. Each action has a form for user input, one or more HTTP requests, and response mapping.
actions: [
{
name: 'createIssue', // Unique action identifier
title: 'Create Issue', // Display title
description: 'Create a new issue in a repository',
renderStrategy: 'auto', // UI rendering ('auto' = standard form)
// Form definition (JSON Schema)
parameters: { /* see §5.2 */ },
// HTTP requests to execute (see §5.3)
requests: [ /* ... */ ],
},
]renderStrategy values:
| Value | Description |
|---|---|
'auto' | Standard auto-generated form (recommended) |
Parameters define the user-facing form using JSON Schema. Extended with custom x-* properties for dynamic data.
parameters: {
type: 'object',
required: ['repository', 'title'],
properties: {
// Simple text input
title: {
type: 'string',
title: 'Issue Title',
description: 'A short descriptive title',
},
// Text area (multiline)
body: {
type: 'string',
title: 'Description',
},
// Dynamic dropdown from RPC source
repository: {
type: 'string',
title: 'Repository',
'x-source': 'rpc_repos_list', // References a source definition
'x-fallback': 'input', // Fallback to text input if source fails
},
// Static dropdown (enum)
priority: {
type: 'string',
title: 'Priority',
enum: ['low', 'medium', 'high', 'critical'],
default: 'medium',
},
// Boolean toggle
isDraft: {
type: 'boolean',
title: 'Draft',
default: false,
},
// Number input
count: {
type: 'number',
title: 'Count',
},
// Array input (comma-separated or JSON)
labels: {
type: 'array',
title: 'Labels',
},
},
}Supported type values:
| Type | Rendered As |
|---|---|
string | Text input (or dropdown if enum provided) |
number | Number input |
boolean | Toggle switch |
array | Multi-value input |
object | Nested form group |
Custom extensions:
| Extension | Type | Description |
|---|---|---|
x-source | string | RPC source key (e.g., 'rpc_channels_list') |
x-fallback | string | Fallback mode if source fails ('input') |
Each action has a requests array. Requests execute sequentially — the response from request N is available as placeholders in request N+1.
Single request:
requests: [
{
url: 'https://api.example.com/issues',
method: 'POST',
headers: {
Authorization: 'Bearer [[accessToken]]',
'Content-Type': 'application/json',
},
bodyType: 'json',
body: {
title: '{{title}}',
body: '{{body}}',
labels: '{{labels}}',
},
mapping: {
issueId: '$.id',
issueUrl: '$.html_url',
},
},
]Chained requests (multi-step):
// Example: Send a direct message on Slack
// Step 1: Open a DM channel with the user
// Step 2: Post a message to that channel
requests: [
// Step 1: Open DM channel
{
url: 'https://slack.com/api/conversations.open',
method: 'POST',
headers: {
Authorization: 'Bearer [[accessToken]]',
'Content-Type': 'application/json',
},
bodyType: 'json',
body: { users: '{{userId}}' },
// Array mapping → values forwarded to next request (NOT persisted)
mapping: [
{ name: 'dmChannelId', value: '$.channel.id' },
],
},
// Step 2: Post message (uses dmChannelId from step 1)
{
url: 'https://slack.com/api/chat.postMessage',
method: 'POST',
headers: {
Authorization: 'Bearer [[accessToken]]',
'Content-Type': 'application/json',
},
bodyType: 'json',
body: {
channel: '{{dmChannelId}}', // ← From step 1's mapping
text: '{{messageText}}', // ← From user's form input
},
mapping: {
messageTs: '$.ts',
channelId: '$.channel',
},
},
]Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
url | string | ✅ | Full URL (supports [[cred]] and {{param}}) |
method | string | ✅ | HTTP method: GET, POST, PUT, PATCH, DELETE |
headers | object | — | Request headers |
queryParams | object | — | URL query parameters |
bodyType | string | — | 'json', 'x-www-form-urlencoded', 'formData' |
body | object | — | Request body (placeholders replaced at runtime) |
mapping | object or array | ✅ | Response extraction (see §5.5) |
There are two placeholder syntaxes:
| Syntax | Source | Persisted? | Example |
|---|---|---|---|
[[key]] | credentials + metadata | N/A | [[accessToken]], [[storeId]] |
{{key}} | User input + runtime context | No | {{channel}}, {{store_url}} |
Placeholder resolution order for {{key}}:
- User's form input (
parameters) - Previous request's mapping output (in chained requests)
auth.configvalues (for registration requests)- System-injected values (
webhookUrl,subdomain,uid)
Type preservation: If a placeholder is the entire value (e.g., body: { data: '{{myObject}}' }), the raw type is preserved — objects remain objects, arrays remain arrays. If a placeholder is part of a larger string (e.g., "Hello {{name}}!"), it's stringified.
Mapping extracts values from API responses. Two formats with different behaviors:
Object mapping — Values are persisted in the database:
| Auth step | Stored in |
|---|---|
get_token, refresh_token, registrationRequests | InstalledMiniApps.credentials |
userDetails | InstalledMiniApps.metadata (full mapping preserved) |
// get_token / refresh_token / registrationRequests → credentials
mapping: {
accessToken: '$.access_token',
webhookId: '$.webhook.id',
}
// userDetails → metadata
mapping: {
uid: '$.user.id',
storeId: '$.user.store.id',
storeName: '$.user.store.title',
}Use object mapping in get_token, refresh_token, registrationRequests, and userDetails.
Array mapping — Values are forwarded to the next request only (not persisted):
mapping: [
{ name: 'channelId', value: '$.channel.id' },
{ name: 'threadTs', value: '$.message.ts' },
]Use array mapping in action requests when you need to chain request outputs.
Dot-path syntax: Values use JSONPath-like syntax starting with $:
| Expression | Description |
|---|---|
$.id | Root-level id field |
$.data.user.name | Nested access |
$.items[0].code | Array index access |
$.channel | Direct field reference |