> ## Documentation Index
> Fetch the complete documentation index at: https://docs.subverseai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Function Actions

> Built-in actions available to your custom function code — connect to HTTP APIs, Airtable, Google Sheets, WhatsApp, Shopify, and SubVerse agents without writing any integration boilerplate

Custom Function Actions are pre-built integrations you can call directly from your custom function code via `subverseActions`. When you build a custom function, you select which actions you want to use and attach the required credentials. The Code Assistant is aware of your selected actions and credentials, so you can describe what you want in plain English and it will generate the correct code for you.

<Info>
  Actions that require credentials will prompt you to select a saved credential when you add the action to your function. Credentials are stored securely and injected at runtime — your code never contains secrets.
</Info>

***

## HTTP Send Request

Make an outbound HTTP request to any URL. Supports all standard methods, custom headers, query parameters, and request body. Optionally authenticates using a stored credential.

**Compatible credentials:** HTTP Basic Auth, HTTP Bearer Auth, HTTP Header Auth (API Key), HTTP Digest Auth, HTTP Query Auth, HTTP Custom Auth

| Parameter                            | Required | Description                                                                                                               |
| ------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------- |
| `options.method`                     | Yes      | HTTP method: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`                                                   |
| `options.url`                        | Yes      | Target URL — must start with `http://` or `https://`                                                                      |
| `options.headers`                    | No       | Array of `{ name, value }` pairs for custom request headers                                                               |
| `options.query`                      | No       | Array of `{ name, value }` pairs appended as URL query parameters                                                         |
| `options.body`                       | No       | Request payload — object (auto-serialised as JSON) or raw string                                                          |
| `credentialId`                       | No       | ID of the saved credential to use                                                                                         |
| `options.options.timeout`            | No       | Request timeout in milliseconds. Default `30000`, max `300000`                                                            |
| `options.options.followRedirects`    | No       | Follow 301/302 redirects. Default `true`                                                                                  |
| `options.options.ignoreSSL`          | No       | Bypass SSL certificate validation. Default `false`                                                                        |
| `options.options.responseFormat`     | No       | Force response format: `autodetect` \| `json` \| `text` \| `base64`. Default `autodetect`. Use `base64` for binary files. |
| `options.options.fullResponse`       | No       | Return `statusCode`, `headers`, and `body` instead of just the body. Default `false`                                      |
| `options.options.ignoreResponseCode` | No       | Don't throw on 4xx/5xx — handle the error response yourself. Default `false`                                              |

```javascript theme={null}
const response = await subverseActions.http.sendRequest({
  credentialId: 'CREDENTIAL_ID', //optional
  options: {
    method: 'POST',
    url: 'https://api.example.com/orders',
    headers: [
      { name: 'custom-headers', value: 'custom-value' }
    ],
    body: {
      customerId: body.params.customer_id,
      status: 'confirmed'
    },
    options: {
      timeout: 10000,
      ignoreResponseCode: true             // handle 4xx without throwing
    }
  }
});

// response.responseCode — HTTP status code
// response.data        — parsed response body
// response.message     — status text
```

***

## Airtable List Records

Fetch a list of records from an Airtable table. Supports filtering, sorting, field selection, and pagination.

| Parameter                         | Required | Description                                          |
| --------------------------------- | -------- | ---------------------------------------------------- |
| `credentialId`                    | Yes      | Airtable credential ID                               |
| `options.baseId`                  | Yes      | Airtable Base ID — e.g. `appXXXXXXXXXXXXXX`          |
| `options.tableIdOrName`           | Yes      | Table name or table ID — e.g. `tblXXXXXXXXXXXXXX`    |
| `options.filters.filterByFormula` | No       | Airtable formula to filter records                   |
| `options.filters.fields`          | No       | Array of field names to return. Omit for all fields  |
| `options.filters.sort`            | No       | Array of `{ "Field Name": "asc" \| "desc" }` objects |
| `options.filters.pageSize`        | No       | Records per page, max `100`                          |
| `options.filters.maxRecords`      | No       | Total cap on records returned                        |
| `options.filters.view`            | No       | Name or ID of a specific view to apply               |

```javascript theme={null}
const result = await subverseActions.airtable.getRecordList({
  credentialId: 'CREDENTIAL_ID',
  options: {
    baseId: 'appXXXXXXXXXXXXXX',
    tableIdOrName: 'Customers',
    filters: {
      filterByFormula: `{Email} = '${body.params.email}'`,
      fields: ['Name', 'Email', 'Status'],
      pageSize: 10
    }
  }
});

// result.records — array of { id, createdTime, fields }
const customer = result.records[0];
```

## Airtable Get Record by ID

Retrieve a single Airtable record by its record ID.

| Parameter               | Required | Description                          |
| ----------------------- | -------- | ------------------------------------ |
| `credentialId`          | Yes      | Airtable credential ID               |
| `options.baseId`        | Yes      | Airtable Base ID                     |
| `options.tableIdOrName` | Yes      | Table name or table ID               |
| `options.recordId`      | Yes      | Record ID — e.g. `recXXXXXXXXXXXXXX` |

```javascript theme={null}
const record = await subverseActions.airtable.getRecordById({
  credentialId: 'CREDENTIAL_ID',
  options: {
    baseId: 'appXXXXXXXXXXXXXX',
    tableIdOrName: 'Orders',
    recordId: body.params.record_id
  }
});

// record.id, record.createdTime, record.fields
```

## Airtable Create Record

Create one or more records in an Airtable table. Use `fields` for a single record or `records` for bulk creation.

| Parameter               | Required | Description                                                |
| ----------------------- | -------- | ---------------------------------------------------------- |
| `credentialId`          | Yes      | Airtable credential ID                                     |
| `options.baseId`        | Yes      | Airtable Base ID                                           |
| `options.tableIdOrName` | Yes      | Table name or table ID                                     |
| `options.fields`        | One of   | Field key-value pairs for a single record                  |
| `options.records`       | One of   | Array of `{ fields: { ... } }` objects for bulk creation   |
| `options.typecast`      | No       | Auto-convert strings to match field types. Default `false` |

```javascript theme={null}
// Single record
const created = await subverseActions.airtable.createRecord({
  credentialId: 'CREDENTIAL_ID',
  options: {
    baseId: 'appXXXXXXXXXXXXXX',
    tableIdOrName: 'Leads',
    fields: {
      Name: body.params.name,
      Email: body.params.email,
      Source: 'Voice Call'
    }
  }
});

// created.id — new record ID
```

## Airtable Update Record

Update specific fields of an existing Airtable record. Only provided fields are changed; others remain untouched.

| Parameter               | Required | Description                                                |
| ----------------------- | -------- | ---------------------------------------------------------- |
| `credentialId`          | Yes      | Airtable credential ID                                     |
| `options.baseId`        | Yes      | Airtable Base ID                                           |
| `options.tableIdOrName` | Yes      | Table name or table ID                                     |
| `options.recordId`      | Yes      | Record ID to update                                        |
| `options.fields`        | Yes      | Object of fields to update                                 |
| `options.typecast`      | No       | Auto-convert strings to match field types. Default `false` |

```javascript theme={null}
const updated = await subverseActions.airtable.updateRecord({
  credentialId: 'CREDENTIAL_ID',
  options: {
    baseId: 'appXXXXXXXXXXXXXX',
    tableIdOrName: 'Orders',
    recordId: body.params.record_id,
    fields: {
      Status: 'Completed',
      ResolvedAt: new Date().toISOString()
    }
  }
});
```

## Airtable Delete Record

Permanently delete a single Airtable record by its record ID.

| Parameter               | Required | Description            |
| ----------------------- | -------- | ---------------------- |
| `credentialId`          | Yes      | Airtable credential ID |
| `options.baseId`        | Yes      | Airtable Base ID       |
| `options.tableIdOrName` | Yes      | Table name or table ID |
| `options.recordId`      | Yes      | Record ID to delete    |

```javascript theme={null}
const result = await subverseActions.airtable.deleteRecord({
  credentialId: 'CREDENTIAL_ID',
  options: {
    baseId: 'appXXXXXXXXXXXXXX',
    tableIdOrName: 'TempRecords',
    recordId: body.params.record_id
  }
});

// result.deleted — true on success
```

***

## Google Sheets Read Rows

Read values from a range in a Google Sheet. Returns a 2D array where each inner array is a row.

| Parameter               | Required | Description                                                     |
| ----------------------- | -------- | --------------------------------------------------------------- |
| `credentialId`          | No       | Required for service account auth. Optional for API key         |
| `options.spreadsheetId` | Yes      | Spreadsheet ID from the URL: `/spreadsheets/d/{spreadsheetId}/` |
| `options.range`         | Yes      | A1 notation range — e.g. `Sheet1!A1:D10` or just `Sheet1`       |

```javascript theme={null}
const data = await subverseActions.googleSheets.readRows({
  credentialId: 'CREDENTIAL_ID',
  options: {
    spreadsheetId: 'YOUR_SPREADSHEET_ID',
    range: 'Customers!A1:D50'
  }
});

// data.values — 2D array; data.values[0] is usually the header row
const headers = data.values[0];
const rows = data.values.slice(1);
```

## Google Sheets Append Rows

Append rows to the end of a Google Sheet after the last row with data.

| Parameter                  | Required | Description                                                                  |
| -------------------------- | -------- | ---------------------------------------------------------------------------- |
| `credentialId`             | Yes      | Google Sheets service account credential ID                                  |
| `options.spreadsheetId`    | Yes      | Spreadsheet ID                                                               |
| `options.range`            | Yes      | Sheet name or range — only the sheet name matters for append (e.g. `Sheet1`) |
| `options.rows`             | Yes      | Array of rows to append. Each row is an array of cell values                 |
| `options.valueInputOption` | No       | `RAW` (as-is) or `USER_ENTERED` (parsed). Default `USER_ENTERED`             |

```javascript theme={null}
const result = await subverseActions.googleSheets.appendRows({
  credentialId: 'CREDENTIAL_ID',
  options: {
    spreadsheetId: 'YOUR_SPREADSHEET_ID',
    range: 'Leads',
    rows: [
      [body.params.name, body.params.email, new Date().toISOString()]
    ]
  }
});

// result.updates.updatedRows — number of rows added
```

## Google Sheets Update Rows

Overwrite existing rows at a specific range. The data dimensions must match the range provided.

| Parameter                  | Required | Description                                          |
| -------------------------- | -------- | ---------------------------------------------------- |
| `credentialId`             | Yes      | Google Sheets service account credential ID          |
| `options.spreadsheetId`    | Yes      | Spreadsheet ID                                       |
| `options.range`            | Yes      | A1 notation range to overwrite — e.g. `Sheet1!A2:C2` |
| `options.rows`             | Yes      | Array of rows. Dimensions must match the range       |
| `options.valueInputOption` | No       | `RAW` or `USER_ENTERED`. Default `USER_ENTERED`      |

```javascript theme={null}
const result = await subverseActions.googleSheets.updateRows({
  credentialId: 'CREDENTIAL_ID',
  options: {
    spreadsheetId: 'YOUR_SPREADSHEET_ID',
    range: `Customers!B${body.params.row_number}:C${body.params.row_number}`,
    rows: [
      ['Completed', new Date().toISOString()]
    ]
  }
});
```

***

## SubVerse Agents Trigger Voice Call

All agent trigger actions authenticate via an `httpHeaderAuth` credential carrying the workspace API key. Set the header name to `x-api-key` and value to your workspace API key.

Trigger an outbound voice call to a customer phone number. The call is queued immediately and dispatched by the voice infrastructure.

| Parameter                           | Required | Description                                                              |
| ----------------------------------- | -------- | ------------------------------------------------------------------------ |
| `credentialId`                      | Yes      | `httpHeaderAuth` credential with `x-api-key` value                       |
| `options.phoneNumber`               | Yes      | Customer number in E.164 format — e.g. `+919876543210`                   |
| `options.agentName`                 | Yes      | Name of the agent (use case) to run for this call                        |
| `options.agentNumber`               | No       | Outbound caller ID. Uses workspace default if omitted                    |
| `options.metadata`                  | No       | Key-value pairs passed into the agent session — use `{{key}}` in prompts |
| `options.scheduleTime`              | No       | ISO 8601 UTC datetime to place the call — e.g. `2025-06-01T09:00:00Z`    |
| `options.startWorkingHour`          | No       | Earliest time to call, `HH:MM` format — e.g. `09:00`                     |
| `options.endWorkingHour`            | No       | Latest time to call, `HH:MM` format — e.g. `18:00`                       |
| `options.timezone`                  | No       | IANA timezone for working hours — e.g. `Asia/Kolkata`                    |
| `options.noOfRetries`               | No       | Retry count on failure. Default `0`                                      |
| `options.callPriority`              | No       | Queue priority `1` (highest) – `100` (lowest). Default `10`              |
| `options.options.initialMessage`    | No       | Opening line spoken when the call connects                               |
| `options.options.additionalContext` | No       | Extra prompt instructions for this call only                             |

```javascript theme={null}
const call = await subverseActions.agent.callOutboundTrigger({
  credentialId: 'CREDENTIAL_ID',
  options: {
    phoneNumber: body.params.phone_number,
    agentName: 'payment-reminder',
    metadata: {
      customerName: body.params.name,
      amountDue: body.params.amount
    },
    options: {
      initialMessage: `Hello ${body.params.name}, this is a reminder about your upcoming payment.`
    },
    startWorkingHour: '09:00',
    endWorkingHour: '18:00',
    timezone: 'Asia/Kolkata'
  }
});

// call.responseCode — 200 on success
// call.data.jobId   — queue job ID for tracking
```

## SubVerse Agents Trigger Chat Message

Send a WhatsApp message or start a chat agent session for a customer.

| Parameter                                   | Required | Description                                                                  |
| ------------------------------------------- | -------- | ---------------------------------------------------------------------------- |
| `credentialId`                              | Yes      | `httpHeaderAuth` credential with `x-api-key` value                           |
| `options.communicationChannel`              | Yes      | Name of the WhatsApp channel in your workspace                               |
| `options.customerNumber`                    | Yes      | Recipient WhatsApp number in E.164 format                                    |
| `options.whatsappOptions.messageType`       | No       | `say` (verbatim) \| `prompt` (LLM-generated) \| `template`. Default `prompt` |
| `options.whatsappOptions.message`           | No       | Message text — required when `messageType` is `say`                          |
| `options.whatsappOptions.additionalContext` | No       | Injected into LLM prompt — used when `messageType` is `prompt`               |
| `options.whatsappOptions.templateId`        | No       | WhatsApp template name — required when `messageType` is `template`           |
| `options.metadata`                          | No       | Key-value pairs passed into the agent session                                |
| `options.scheduleTime`                      | No       | ISO 8601 datetime to schedule the send                                       |
| `options.agentName`                         | No       | Override the channel's default agent                                         |

```javascript theme={null}
const chat = await subverseActions.agent.chatTrigger({
  credentialId: 'CREDENTIAL_ID',
  options: {
    communicationChannel: 'whatsapp-support',
    customerNumber: body.params.whatsapp_number,
    whatsappOptions: {
      messageType: 'say',
      message: `Hi ${body.params.name}, your order #${body.params.order_id} has been shipped!`
    },
    metadata: {
      customerName: body.params.name
    }
  }
});

// chat.data.sessionId — session ID for the triggered conversation
```

## SubVerse Agents Trigger Email

Send an email or start an email agent session for a customer.

| Parameter                                | Required | Description                                                            |
| ---------------------------------------- | -------- | ---------------------------------------------------------------------- |
| `credentialId`                           | Yes      | `httpHeaderAuth` credential with `x-api-key` value                     |
| `options.communicationChannel`           | Yes      | Name of the Email channel in your workspace                            |
| `options.customerEmail`                  | Yes      | Recipient email address                                                |
| `options.emailOptions.messageType`       | No       | `say` (verbatim body) \| `prompt` (LLM-generated). Default `prompt`    |
| `options.emailOptions.subject`           | No       | Email subject line                                                     |
| `options.emailOptions.body`              | No       | Email body (HTML or plain text) — required when `messageType` is `say` |
| `options.emailOptions.additionalContext` | No       | Injected into LLM prompt — used when `messageType` is `prompt`         |
| `options.emailOptions.replyTo`           | No       | Reply-To address                                                       |
| `options.emailOptions.cc`                | No       | CC recipients — comma-separated                                        |
| `options.metadata`                       | No       | Key-value pairs passed into the agent session                          |
| `options.scheduleTime`                   | No       | ISO 8601 datetime to schedule the send                                 |

```javascript theme={null}
const email = await subverseActions.agent.emailTrigger({
  credentialId: 'CREDENTIAL_ID',
  options: {
    communicationChannel: 'email-support',
    customerEmail: body.params.email,
    emailOptions: {
      messageType: 'say',
      subject: `Your order #${body.params.order_id} is confirmed`,
      body: `<p>Hi ${body.params.name},</p><p>Thank you for your order. We'll notify you when it ships.</p>`
    },
    metadata: {
      customerName: body.params.name
    }
  }
});

// email.data.sessionId — session ID for the triggered conversation
```

***

## Email Send

Send an email directly through an SMTP server using a saved **Email (SMTP / IMAP)** credential. This action is useful for transactional emails, alerts, and reports from a custom function.

**Compatible credentials:** [Email (SMTP / IMAP)](/credentials/types/email-smtp)

| Parameter                   | Required | Description                                                                                                                                               |
| --------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `credentialId`              | Yes      | Email (SMTP / IMAP) credential ID                                                                                                                         |
| `options.fromEmail`         | No       | Sender address in `sender@example.com` or `Name <sender@example.com>` format. Defaults to the credential username when omitted                            |
| `options.toEmail`           | Yes      | Recipient email address                                                                                                                                   |
| `options.subject`           | Yes      | Email subject line                                                                                                                                        |
| `options.emailFormat`       | No       | `text`, `html`, or `both`. Default `both`                                                                                                                 |
| `options.text`              | No       | Plain text body. Provide it when `emailFormat` is `text` or `both`                                                                                        |
| `options.html`              | No       | HTML body. Provide it when `emailFormat` is `html` or `both`                                                                                              |
| `options.ccEmail`           | No       | CC recipient address                                                                                                                                      |
| `options.bccEmail`          | No       | BCC recipient address                                                                                                                                     |
| `options.replyTo`           | No       | Reply-To address                                                                                                                                          |
| `options.attachments`       | No       | Array of `{ fileUrl, fileName? }` objects. `fileUrl` is required and must be a valid URL; `fileName` is optional and is derived from the URL when omitted |
| `options.ignoreSSL`         | No       | Bypass SSL certificate validation. Default `false`                                                                                                        |
| `options.appendAttribution` | No       | Append a "Sent via SubverseAI" footer. Default `false`                                                                                                    |

```javascript theme={null}
const result = await subverseActions.email.send({
  credentialId: 'CREDENTIAL_ID',
  options: {
    toEmail: body.params.customer_email,
    subject: `Your order #${body.params.order_id} is confirmed`,
    emailFormat: 'both',
    text: `Hi ${body.params.name}, your order has been confirmed.`,
    html: `<p>Hi ${body.params.name},</p><p>Your order <strong>#${body.params.order_id}</strong> is confirmed.</p>`,
    attachments: [
      {
        fileUrl: body.params.invoice_url,
        fileName: 'invoice.pdf'
      }
    ]
  }
});

// result.messageId — SMTP message ID
// result.accepted — array of accepted addresses
// result.rejected — array of rejected addresses
```

***

## Shopify

The Shopify actions below connect to a Shopify store via a saved Shopify credential. All actions support `credentialId` plus an `options` object.

**Compatible credentials:** Shopify API Key, Shopify Access Token, Shopify OAuth2

### Shopify Create Order

Create a new order in Shopify. Requires at least one line item. Supports billing/shipping addresses, discount codes, fulfillment options, and email notifications.

| Parameter                        | Required | Description                                                                                                    |
| -------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------- |
| `credentialId`                   | Yes      | Credential ID for the Shopify store                                                                            |
| `options.lineItems`              | Yes      | Array of line items. Each item requires `quantity`; `variantId`, `productId`, `title`, or `price` are optional |
| `options.email`                  | No       | Customer email address                                                                                         |
| `options.fulfillmentStatus`      | No       | `fulfilled`, `null`, `partial`, or `restocked`                                                                 |
| `options.inventoryBehaviour`     | No       | `bypass`, `decrementIgnoringPolicy`, or `decrementObeyingPolicy`                                               |
| `options.locationId`             | No       | ID of the location that processed the order                                                                    |
| `options.note`                   | No       | Order note                                                                                                     |
| `options.sendFulfillmentReceipt` | No       | Send a shipping confirmation email                                                                             |
| `options.sendReceipt`            | No       | Send an order confirmation email                                                                               |
| `options.sourceName`             | No       | Source identifier, e.g. `web`                                                                                  |
| `options.tags`                   | No       | Comma-separated tags                                                                                           |
| `options.test`                   | No       | Mark as a test order. Default `true`                                                                           |
| `options.billingAddress`         | No       | Billing address object                                                                                         |
| `options.shippingAddress`        | No       | Shipping address object                                                                                        |
| `options.discountCodes`          | No       | Array of `{ amount, code, type }` discounts                                                                    |

```javascript theme={null}
const order = await subverseActions.shopify.createOrder({
  credentialId: 'CREDENTIAL_ID',
  options: {
    lineItems: [{ variantId: body.params.variant_id, quantity: 1 }],
    email: body.params.email,
    shippingAddress: {
      firstName: body.params.first_name,
      lastName: body.params.last_name,
      city: body.params.city,
      country: body.params.country
    },
    sendReceipt: true
  }
});

// order.id — new Shopify order ID
```

### Shopify Get Order

Retrieve a single Shopify order by its ID.

| Parameter         | Required | Description                                       |
| ----------------- | -------- | ------------------------------------------------- |
| `credentialId`    | Yes      | Credential ID for the Shopify store               |
| `options.orderId` | Yes      | Numeric ID of the Shopify order                   |
| `options.fields`  | No       | Comma-separated fields to include in the response |

```javascript theme={null}
const order = await subverseActions.shopify.getOrder({
  credentialId: 'CREDENTIAL_ID',
  options: {
    orderId: body.params.order_id,
    fields: 'id,email,financial_status'
  }
});
```

### Shopify Get All Orders

Retrieve a list of Shopify orders with optional filtering and pagination.

| Parameter                                           | Required | Description                                    |
| --------------------------------------------------- | -------- | ---------------------------------------------- |
| `credentialId`                                      | Yes      | Credential ID for the Shopify store            |
| `options.returnAll`                                 | No       | Auto-paginate to fetch all matching orders     |
| `options.limit`                                     | No       | Max orders to return (default `50`, max `250`) |
| `options.status`                                    | No       | `open`, `closed`, `cancelled`, or `any`        |
| `options.financialStatus`                           | No       | e.g. `paid`, `pending`, `refunded`             |
| `options.fulfillmentStatus`                         | No       | e.g. `shipped`, `unshipped`, `partial`         |
| `options.createdAtMin` / `options.createdAtMax`     | No       | ISO 8601 datetime range for created at         |
| `options.updatedAtMin` / `options.updatedAtMax`     | No       | ISO 8601 datetime range for updated at         |
| `options.processedAtMin` / `options.processedAtMax` | No       | ISO 8601 datetime range for processed at       |
| `options.sinceId`                                   | No       | Return only orders after this ID               |
| `options.ids`                                       | No       | Comma-separated order IDs                      |
| `options.attributionAppId`                          | No       | Filter by attribution app ID                   |
| `options.fields`                                    | No       | Comma-separated fields to include              |

```javascript theme={null}
const orders = await subverseActions.shopify.getAllOrders({
  credentialId: 'CREDENTIAL_ID',
  options: {
    status: 'open',
    limit: 50
  }
});

// orders — array of order objects
```

### Shopify Update Order

Update an existing Shopify order by ID.

| Parameter                 | Required | Description                                  |
| ------------------------- | -------- | -------------------------------------------- |
| `credentialId`            | Yes      | Credential ID for the Shopify store          |
| `options.orderId`         | Yes      | Numeric ID of the order to update            |
| `options.email`           | No       | Updated customer email                       |
| `options.note`            | No       | Internal note                                |
| `options.tags`            | No       | Comma-separated tags replacing existing tags |
| `options.sourceName`      | No       | Source identifier                            |
| `options.locationId`      | No       | Location ID                                  |
| `options.shippingAddress` | No       | Updated shipping address                     |

```javascript theme={null}
const updated = await subverseActions.shopify.updateOrder({
  credentialId: 'CREDENTIAL_ID',
  options: {
    orderId: body.params.order_id,
    note: 'Customer requested expedited handling',
    tags: 'vip,priority'
  }
});
```

### Shopify Delete Order

Permanently delete a Shopify order. Only test orders can be deleted via the API.

| Parameter         | Required | Description                         |
| ----------------- | -------- | ----------------------------------- |
| `credentialId`    | Yes      | Credential ID for the Shopify store |
| `options.orderId` | Yes      | Numeric ID of the order to delete   |

```javascript theme={null}
const result = await subverseActions.shopify.deleteOrder({
  credentialId: 'CREDENTIAL_ID',
  options: {
    orderId: body.params.order_id
  }
});

// result.success — true on success
```

### Shopify Create Product

Create a new product in your Shopify store. A title is required.

| Parameter                | Required | Description                                                |
| ------------------------ | -------- | ---------------------------------------------------------- |
| `credentialId`           | Yes      | Credential ID for the Shopify store                        |
| `options.title`          | Yes      | Product name                                               |
| `options.bodyHtml`       | No       | HTML description                                           |
| `options.handle`         | No       | URL-friendly handle                                        |
| `options.productType`    | No       | Product type category                                      |
| `options.publishedAt`    | No       | ISO 8601 datetime to publish. Set `null` to unpublish      |
| `options.publishedScope` | No       | `global` (Online Store + POS) or `web` (Online Store only) |
| `options.tags`           | No       | Comma-separated tags                                       |
| `options.templateSuffix` | No       | Liquid template suffix                                     |
| `options.vendor`         | No       | Brand or vendor name                                       |

```javascript theme={null}
const product = await subverseActions.shopify.createProduct({
  credentialId: 'CREDENTIAL_ID',
  options: {
    title: body.params.title,
    bodyHtml: body.params.description,
    vendor: body.params.vendor,
    productType: body.params.product_type
  }
});

// product.id — new Shopify product ID
```

### Shopify Get Product

Retrieve a single Shopify product by its ID.

| Parameter           | Required | Description                                       |
| ------------------- | -------- | ------------------------------------------------- |
| `credentialId`      | Yes      | Credential ID for the Shopify store               |
| `options.productId` | Yes      | Numeric ID of the Shopify product                 |
| `options.fields`    | No       | Comma-separated fields to include in the response |

```javascript theme={null}
const product = await subverseActions.shopify.getProduct({
  credentialId: 'CREDENTIAL_ID',
  options: {
    productId: body.params.product_id,
    fields: 'id,title,variants'
  }
});
```

### Shopify Get All Products

Retrieve a list of Shopify products with optional filtering and pagination.

| Parameter                                           | Required | Description                                      |
| --------------------------------------------------- | -------- | ------------------------------------------------ |
| `credentialId`                                      | Yes      | Credential ID for the Shopify store              |
| `options.returnAll`                                 | No       | Auto-paginate to fetch all matching products     |
| `options.limit`                                     | No       | Max products to return (default `50`, max `250`) |
| `options.title`                                     | No       | Filter by exact title                            |
| `options.vendor`                                    | No       | Filter by vendor                                 |
| `options.handle`                                    | No       | Filter by handle                                 |
| `options.productType`                               | No       | Filter by product type                           |
| `options.status`                                    | No       | `active`, `archived`, or `draft`                 |
| `options.publishedStatus`                           | No       | `published`, `unpublished`, or `any`             |
| `options.ids`                                       | No       | Comma-separated product IDs                      |
| `options.sinceId`                                   | No       | Return only products after this ID               |
| `options.createdAtMin` / `options.createdAtMax`     | No       | ISO 8601 datetime range                          |
| `options.updatedAtMin` / `options.updatedAtMax`     | No       | ISO 8601 datetime range                          |
| `options.publishedAtMin` / `options.publishedAtMax` | No       | ISO 8601 datetime range                          |
| `options.fields`                                    | No       | Comma-separated fields to include                |

```javascript theme={null}
const products = await subverseActions.shopify.getAllProducts({
  credentialId: 'CREDENTIAL_ID',
  options: {
    vendor: body.params.vendor,
    status: 'active',
    limit: 50
  }
});

// products — array of product objects
```

### Shopify Update Product

Update an existing Shopify product by ID.

| Parameter                | Required | Description                                |
| ------------------------ | -------- | ------------------------------------------ |
| `credentialId`           | Yes      | Credential ID for the Shopify store        |
| `options.productId`      | Yes      | Numeric ID of the product to update        |
| `options.title`          | No       | Updated product title                      |
| `options.bodyHtml`       | No       | Updated HTML description                   |
| `options.handle`         | No       | Updated URL-friendly handle                |
| `options.productType`    | No       | Updated product type                       |
| `options.publishedAt`    | No       | ISO 8601 datetime. Set `null` to unpublish |
| `options.publishedScope` | No       | `global` or `web`                          |
| `options.tags`           | No       | Updated comma-separated tags               |
| `options.templateSuffix` | No       | Updated Liquid template suffix             |
| `options.vendor`         | No       | Updated vendor name                        |

```javascript theme={null}
const updated = await subverseActions.shopify.updateProduct({
  credentialId: 'CREDENTIAL_ID',
  options: {
    productId: body.params.product_id,
    title: body.params.title,
    tags: body.params.tags
  }
});
```

### Shopify Delete Product

Permanently delete a Shopify product by its ID. This cannot be undone.

| Parameter           | Required | Description                         |
| ------------------- | -------- | ----------------------------------- |
| `credentialId`      | Yes      | Credential ID for the Shopify store |
| `options.productId` | Yes      | Numeric ID of the product to delete |

```javascript theme={null}
const result = await subverseActions.shopify.deleteProduct({
  credentialId: 'CREDENTIAL_ID',
  options: {
    productId: body.params.product_id
  }
});

// result.success — true on success
```

***

## WhatsApp

The WhatsApp actions let you send messages directly through the Meta WhatsApp Business Cloud API using a saved **WhatsApp API** credential. All three actions require a `credentialId`, the recipient's phone number, and your sender's **Phone Number ID** (not stored in the credential — supply it explicitly in `options`).

**Compatible credentials:** [WhatsApp API](/credentials/types/whatsapp-api) (`whatsAppApi`, with Access Token and Business Account ID)

### WhatsApp Send Text Message

Send a plain text message to a WhatsApp number.

| Parameter               | Required | Description                                                   |
| ----------------------- | -------- | ------------------------------------------------------------- |
| `credentialId`          | Yes      | WhatsApp credential ID                                        |
| `options.phoneNumberId` | Yes      | Your WhatsApp Business sender phone number ID                 |
| `options.to`            | Yes      | Recipient phone number in E.164 format — e.g. `+919876543210` |
| `options.message`       | Yes      | The text content to send                                      |
| `options.previewUrl`    | No       | Show a URL preview inside the message. Default `false`        |

```javascript theme={null}
const result = await subverseActions.whatsapp.sendTextMessage({
  credentialId: 'CREDENTIAL_ID',
  options: {
    phoneNumberId: '1234567890',
    to: body.params.customer_number,
    message: `Hi ${body.params.name}, your booking is confirmed for ${body.params.date}.`
  }
});

// result.messages[0].id — WhatsApp message ID
// result.contacts[0].wa_id — recipient's WhatsApp ID
```

### WhatsApp Send Template Message

Send an approved WhatsApp message template. Templates must be created and approved in your Meta Business account before use.

| Parameter               | Required | Description                                                                                                                            |
| ----------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `credentialId`          | Yes      | WhatsApp credential ID                                                                                                                 |
| `options.phoneNumberId` | Yes      | Your WhatsApp Business sender phone number ID                                                                                          |
| `options.to`            | Yes      | Recipient phone number in E.164 format                                                                                                 |
| `options.templateName`  | Yes      | Exact name of the approved template                                                                                                    |
| `options.languageCode`  | Yes      | Template language code — e.g. `en_US`                                                                                                  |
| `options.components`    | No       | Array of component objects to fill template variables. Each object has a `type` (`header`, `body`, or `button`) and `parameters` array |

```javascript theme={null}
const result = await subverseActions.whatsapp.sendTemplateMessage({
  credentialId: 'CREDENTIAL_ID',
  options: {
    phoneNumberId: '1234567890',
    to: body.params.customer_number,
    templateName: 'order_shipped',
    languageCode: 'en_US',
    components: [
      {
        type: 'body',
        parameters: [
          { type: 'text', text: body.params.order_id },
          { type: 'text', text: body.params.tracking_number }
        ]
      }
    ]
  }
});

// result.messages[0].id — WhatsApp message ID
```

### WhatsApp Send Media Message

Send an image, video, audio file, document, or sticker to a WhatsApp number.

| Parameter               | Required | Description                                                                             |
| ----------------------- | -------- | --------------------------------------------------------------------------------------- |
| `credentialId`          | Yes      | WhatsApp credential ID                                                                  |
| `options.phoneNumberId` | Yes      | Your WhatsApp Business sender phone number ID                                           |
| `options.to`            | Yes      | Recipient phone number in E.164 format                                                  |
| `options.mediaType`     | Yes      | Type of media: `image`, `video`, `audio`, `document`, or `sticker`                      |
| `options.mediaUrl`      | One of   | Public URL of the media file                                                            |
| `options.mediaId`       | One of   | WhatsApp media ID of a previously uploaded file. Provide either `mediaUrl` or `mediaId` |
| `options.caption`       | No       | Caption text shown with the media (supported for `image`, `video`, `document`)          |
| `options.filename`      | No       | Display filename shown to the recipient (documents only)                                |

```javascript theme={null}
const result = await subverseActions.whatsapp.sendMediaMessage({
  credentialId: 'CREDENTIAL_ID',
  options: {
    phoneNumberId: '1234567890',
    to: body.params.customer_number,
    mediaType: 'document',
    mediaUrl: body.params.invoice_url,
    caption: `Invoice for order #${body.params.order_id}`,
    filename: `invoice-${body.params.order_id}.pdf`
  }
});

// result.messages[0].id — WhatsApp message ID
```

***

## Freshdesk

The Freshdesk actions connect to your Freshdesk support desk using a saved **Freshdesk API** credential. All actions require a `credentialId` plus an `options` object.

**Compatible credentials:** [Freshdesk API](/credentials/types/freshdesk-api)

### Freshdesk Create Ticket

Create a new support ticket in Freshdesk. Requires a requester identifier and value.

| Parameter                              | Required | Description                                                                                                                 |
| -------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------- |
| `credentialId`                         | Yes      | Freshdesk API credential ID                                                                                                 |
| `options.requester`                    | No       | Requester identifier: `email`, `facebookId`, `phone`, `requesterId`, `twitterId`, `uniqueExternalId`. Default `requesterId` |
| `options.requesterIdentificationValue` | Yes      | Value for the selected requester identifier                                                                                 |
| `options.status`                       | No       | `open`, `pending`, `resolved`, or `closed`. Default `open`                                                                  |
| `options.priority`                     | No       | `low`, `medium`, `high`, or `urgent`. Default `low`                                                                         |
| `options.source`                       | No       | `chat`, `email`, `feedbackWidget`, `mobileHelp`, `OutboundEmail`, `phone`, or `portal`. Default `portal`                    |
| `options.name`                         | No       | Name of the requester                                                                                                       |
| `options.subject`                      | No       | Subject of the ticket                                                                                                       |
| `options.description`                  | No       | HTML content of the ticket                                                                                                  |
| `options.type`                         | No       | Ticket type, e.g. `Question`, `Incident`, `Problem`, `Feature Request`, `Refund`                                            |
| `options.agent`                        | No       | Agent ID to assign the ticket to                                                                                            |
| `options.company`                      | No       | Company ID of the requester                                                                                                 |
| `options.product`                      | No       | Product ID associated with the ticket                                                                                       |
| `options.group`                        | No       | Group ID to assign the ticket to                                                                                            |
| `options.ccEmails`                     | No       | Comma-separated CC email addresses                                                                                          |
| `options.tags`                         | No       | Comma-separated tags                                                                                                        |
| `options.dueBy`                        | No       | ISO 8601 datetime when the ticket is due                                                                                    |
| `options.frDueBy`                      | No       | ISO 8601 datetime when the first response is due                                                                            |
| `options.emailConfigId`                | No       | Email config ID                                                                                                             |

```javascript theme={null}
const ticket = await subverseActions.freshdesk.createTicket({
  credentialId: 'CREDENTIAL_ID',
  options: {
    requester: 'email',
    requesterIdentificationValue: body.params.customer_email,
    subject: `Support request from ${body.params.customer_name}`,
    description: `<p>${body.params.issue_description}</p>`,
    priority: 'high',
    source: 'phone',
    type: 'Incident'
  }
});

// ticket.id — new Freshdesk ticket ID
```

### Freshdesk Get Ticket

Retrieve a single Freshdesk ticket by ID.

| Parameter          | Required | Description                  |
| ------------------ | -------- | ---------------------------- |
| `credentialId`     | Yes      | Freshdesk API credential ID  |
| `options.ticketId` | Yes      | ID of the ticket to retrieve |

```javascript theme={null}
const ticket = await subverseActions.freshdesk.getTicket({
  credentialId: 'CREDENTIAL_ID',
  options: {
    ticketId: body.params.ticket_id
  }
});
```

### Freshdesk Get All Tickets

List Freshdesk tickets with optional filters and pagination.

| Parameter                | Required | Description                                                                      |
| ------------------------ | -------- | -------------------------------------------------------------------------------- |
| `credentialId`           | Yes      | Freshdesk API credential ID                                                      |
| `options.returnAll`      | No       | Auto-paginate to fetch all matching tickets                                      |
| `options.limit`          | No       | Max tickets to return (default `5`, max `100`)                                   |
| `options.companyId`      | No       | Filter by company ID                                                             |
| `options.include`        | No       | Array of related data to include: `company`, `description`, `requester`, `stats` |
| `options.order`          | No       | Sort order: `asc` or `desc`. Default `desc`                                      |
| `options.orderBy`        | No       | Sort by `createdAt`, `dueBy`, or `updatedAt`                                     |
| `options.requesterEmail` | No       | Filter by requester email address                                                |
| `options.requesterId`    | No       | Filter by requester ID                                                           |
| `options.updatedSince`   | No       | ISO 8601 timestamp — tickets updated after this time                             |

```javascript theme={null}
const tickets = await subverseActions.freshdesk.getAllTickets({
  credentialId: 'CREDENTIAL_ID',
  options: {
    requesterEmail: body.params.customer_email,
    limit: 10
  }
});

// tickets — array of ticket objects
```

### Freshdesk Update Ticket

Update an existing Freshdesk ticket by ID. Only provided fields are changed.

| Parameter                              | Required | Description                                                                            |
| -------------------------------------- | -------- | -------------------------------------------------------------------------------------- |
| `credentialId`                         | Yes      | Freshdesk API credential ID                                                            |
| `options.ticketId`                     | Yes      | ID of the ticket to update                                                             |
| `options.requester`                    | No       | Requester identifier. If provided, `requesterIdentificationValue` is also required     |
| `options.requesterIdentificationValue` | No       | Required when `requester` is provided                                                  |
| `options.status`                       | No       | `open`, `pending`, `resolved`, or `closed`                                             |
| `options.priority`                     | No       | `low`, `medium`, `high`, or `urgent`                                                   |
| `options.source`                       | No       | `chat`, `email`, `feedbackWidget`, `mobileHelp`, `OutboundEmail`, `phone`, or `portal` |
| `options.name`                         | No       | Name of the requester                                                                  |
| `options.subject`                      | No       | Subject of the ticket                                                                  |
| `options.description`                  | No       | HTML content of the ticket                                                             |
| `options.type`                         | No       | Ticket type                                                                            |
| `options.agent`                        | No       | Agent ID to assign the ticket to                                                       |
| `options.company`                      | No       | Company ID of the requester                                                            |
| `options.product`                      | No       | Product ID associated with the ticket                                                  |
| `options.group`                        | No       | Group ID to assign the ticket to                                                       |
| `options.ccEmails`                     | No       | Comma-separated CC email addresses                                                     |
| `options.tags`                         | No       | Comma-separated tags                                                                   |
| `options.dueBy`                        | No       | ISO 8601 datetime when the ticket is due                                               |
| `options.frDueBy`                      | No       | ISO 8601 datetime when the first response is due                                       |
| `options.emailConfigId`                | No       | Email config ID                                                                        |

```javascript theme={null}
const updated = await subverseActions.freshdesk.updateTicket({
  credentialId: 'CREDENTIAL_ID',
  options: {
    ticketId: body.params.ticket_id,
    status: 'resolved',
    priority: 'medium'
  }
});
```

### Freshdesk Delete Ticket

Delete a Freshdesk ticket by ID.

| Parameter          | Required | Description                 |
| ------------------ | -------- | --------------------------- |
| `credentialId`     | Yes      | Freshdesk API credential ID |
| `options.ticketId` | Yes      | ID of the ticket to delete  |

```javascript theme={null}
const result = await subverseActions.freshdesk.deleteTicket({
  credentialId: 'CREDENTIAL_ID',
  options: {
    ticketId: body.params.ticket_id
  }
});

// result.success — true on success
```

### Freshdesk Add Ticket Note

Add a reply or private note to a Freshdesk ticket.

| Parameter              | Required | Description                                                                     |
| ---------------------- | -------- | ------------------------------------------------------------------------------- |
| `credentialId`         | Yes      | Freshdesk API credential ID                                                     |
| `options.ticketId`     | Yes      | ID of the ticket to add the note to                                             |
| `options.noteBody`     | Yes      | Content of the note or reply                                                    |
| `options.private`      | No       | If `true`, the note is private (internal). Default `false`                      |
| `options.notifyEmails` | No       | Comma-separated email addresses to notify                                       |
| `options.incoming`     | No       | Whether the note appears as created from outside the web portal. Default `true` |

```javascript theme={null}
const note = await subverseActions.freshdesk.addTicketNote({
  credentialId: 'CREDENTIAL_ID',
  options: {
    ticketId: body.params.ticket_id,
    noteBody: `Customer called about ${body.params.issue}. Escalated to L2.`,
    private: true
  }
});

// note.id — new note ID
```

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Custom Functions" icon="code" href="/integrations/agentic-functions/custom-functions">
    Write and test custom function code using these actions
  </Card>

  <Card title="Credentials" icon="key" href="/credentials/overview">
    Set up and manage the credentials used by your actions
  </Card>
</CardGroup>
