# RevCent MCP Operation: `EditFunction`

This document describes the `EditFunction` MCP operation, every input field from the operation schema, and the practical Function configuration rules from the RevCent Functions knowledge base.

> Scope: This document intentionally covers only the `EditFunction` operation.

---

## Operation Summary

`EditFunction` edits a previously created RevCent Function using its 20-character `function_id`.

Use `EditFunction` after `CreateFunction` to configure or modify:

- Function name and description.
- Enabled status.
- JavaScript function code.
- Event source / trigger type.
- Account event trigger notations.
- Account event filters.
- Account event timing options.
- Schedule cron expression and timezone.
- Dependencies.
- Environment variables.
- Function URL / webhook IP restrictions.
- API/AI custom arguments.

Important edit behavior:

- `function_id` is required.
- Only include properties you want to modify.
- Omitted fields remain unchanged.
- Some array fields replace the existing values when provided.
- `environment_variables` are upserted, not fully replaced.
- `dependencies` replace the existing dependency list when provided.
- `custom_arguments` replace the existing custom argument list when provided.

---

## Required Fields

The `EditFunction` schema requires only:

| Field | Type | Required | Notes |
|---|---:|---:|---|
| `function_id` | string | Yes | 20-character Function ID to edit. |

All other fields are optional and should only be included when you want to modify them.

---

## Complete Input Schema Field Reference

### `function_id`

**Type:** `string`  
**Required:** Yes  
**Length:** 20 characters

The ID of the Function being edited.

```json
"function_id": "XXXXXXXXXXXXXXXXXXXX"
```

Important behavior:

- This is the only required field.
- It identifies the existing Function to update.
- Do not include unrelated fields unless you intend to change them.

---

### `name`

**Type:** `string`  
**Required:** No

The Function name.

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "name": "Slack Alert - Chargeback Created"
}
```

Important behavior:

- Must be unique from other Function names.
- Omit this field if the name should remain unchanged.

Recommended naming pattern:

```text
<Trigger or Source> - <Action or Destination> - <Purpose>
```

Examples:

```text
Account Event - Slack Alert - Chargeback Created
Email Template - Custom Data - Receipt Personalization
Schedule - Daily Report - Revenue Summary
API Direct - Normalize Payload - Partner Webhook
```

---

### `description`

**Type:** `string`  
**Required:** No

The Function description.

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "description": "Posts a message to Slack when a chargeback is created."
}
```

Recommended content:

- Trigger or event source.
- External systems involved.
- Important inputs.
- Expected output.
- Required dependencies.
- Required environment variables.
- Whether the Function is for API/AI, account events, email templates, schedules, URLs, payment profiles, or another source.

---

### `enabled`

**Type:** `boolean`  
**Required:** No

Whether the Function is enabled.

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "enabled": true
}
```

Behavior:

- `true`: the Function can run when triggered.
- `false`: the Function should not run.
- Use `false` while drafting or testing configuration.
- Omit this field if enabled status should remain unchanged.

---

### `function_code`

**Type:** `string`  
**Required:** No

The JavaScript code of the Function.

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "function_code": "exports.handler = async function(event, context) { return { success: true }; };"
}
```

## Important: Include the Execution Handler

RevCent does not wrap user code in a handler automatically. The submitted `function_code` must include an exported handler:

```javascript
exports.handler = async function(event, context) {
  return {
    success: true,
    message: "Function completed."
  };
};
```

The handler receives:

```text
event
context
callback, only when using callback-style completion
```

Submit complete handler-based Function code:

```javascript
exports.handler = async function(event, context) {
  try {
    return {
      success: true
    };
  } catch (error) {
    throw error;
  }
};
```

Do not submit only the inner logic:

```javascript
return {
  success: true,
  message: "Function completed."
};
```

Important requirements:

- The Function code must include `exports.handler`.
- A Function can complete by returning a value, throwing an error, or calling `callback(error, response)`.
- Use one completion style intentionally for each execution path.
- If using `callback`, return afterward when code below should not continue.
- Use CommonJS `require()` for dependencies.
- Do not use ESM `import` syntax.

Basic successful response:

```javascript
exports.handler = async function(event, context) {
  return {
    success: true,
    message: "Function completed."
  };
};
```

Basic error response:

```javascript
exports.handler = async function(event, context) {
  throw new Error("Missing required input.");
};
```

Recommended error handling:

```javascript
exports.handler = async function(event, context) {
  try {
    // Function logic here
    return {
      success: true
    };
  } catch (error) {
    throw error;
  }
};
```

---

## `event_source`

**Type:** `string` enum  
**Required:** No

Determines how the Function is triggered, meaning how the code is executed.

Allowed values:

```text
account_event
api_direct
email_template
payment_profile
function_url
schedule
```

> Note: The operation description mentions URL and Webhook as trigger options. In the schema enum, the URL/webhook-style external request source is represented by `function_url`.

---


# Detailed Event Source and Event Body Reference

Every Function trigger type provides a different `event` payload shape to the Function runtime.

Function code must include a handler that receives these runtime arguments:

```javascript
event
context
callback
```

RevCent does not add the handler automatically. Use `exports.handler = async function(event, context) { ... }` for return/throw style, or include `callback` as the third argument only when the code calls `callback(error, response)`.

Use the event-body JSON link for the configured trigger type as the source of truth for the runtime payload.

---

## `account_event`

### Event Body JSON

Account-event Functions use an event body JSON determined by the first word in the account event notation.

Pattern:

```text
https://revcent.com/documentation/files/function/event/account_event/<item_type>.json
```

Examples:

| Account Event Notation | Item Type | Event Body JSON |
|---|---|---|
| `sale.created.success` | `sale` | https://revcent.com/documentation/files/function/event/account_event/sale.json |
| `customer.created` | `customer` | https://revcent.com/documentation/files/function/event/account_event/customer.json |
| `shipping.updated.shipped` | `shipping` | https://revcent.com/documentation/files/function/event/account_event/shipping.json |
| `subscription.updated.renewed.success` | `subscription` | https://revcent.com/documentation/files/function/event/account_event/subscription.json |
| `subscription_renewal.updated.success` | `subscription_renewal` | https://revcent.com/documentation/files/function/event/account_event/subscription_renewal.json |
| `trial.updated.expired.success` | `trial` | https://revcent.com/documentation/files/function/event/account_event/trial.json |

### Runtime Event Structure

Account-event Functions generally receive:

```javascript
event.data.item_type
event.data.item_id
event.data.item_details
```

Example:

```javascript
let item = event.data.item_details;

return {
  customer_email: item.customer.email
};
```

### Typical Use Cases

- Sales notifications.
- Fraud alerts.
- Subscription lifecycle processing.
- Shipping updates.
- Customer-change processing.
- CRM synchronization.
- Slack alerts.

### Best Practices

- Use the most specific notation available.
- Validate required nested properties before use.
- Expect different payload structures depending on item type.
- Use the linked event-body JSON as the source of truth.

---

## `api_direct`

### Event Body JSON

Primary API-direct event body:

https://revcent.com/documentation/files/function/event/api_direct.json

> Note: the CDN URL may return a restricted response depending on retrieval method, but this is still the documented payload reference.

### Runtime Event Structure

API-direct Functions can be triggered explicitly through API/MCP, AI tool execution, or used as filter functions in AI Assistants and AI Voice Agents.

Typical runtime values for direct triggering may include:

```javascript
event.data
event.data.custom_arguments
event.data.item_type
event.data.item_id
event.data.item_details
```

depending on how the Function is triggered.

### API Direct as an AI Assistant / AI Voice Agent Filter Function

An `api_direct` Function can also be used as a filter Function for:

- AI Assistants
- AI Voice Agents

When used as a filter Function, the event body is based on the `item_type` and `item_id` being evaluated. This is similar to an `account_event` event body, except account-event notations are not present.

Filter Function event body URL pattern:

```text
https://revcent.com/documentation/files/function/event/filter/<item_type>.json
```

Examples:

| Filter item type | Filter Function event body JSON |
|---|---|
| `sale` | https://revcent.com/documentation/files/function/event/filter/sale.json |
| `customer` | https://revcent.com/documentation/files/function/event/filter/customer.json |
| `shipping` | https://revcent.com/documentation/files/function/event/filter/shipping.json |
| `subscription` | https://revcent.com/documentation/files/function/event/filter/subscription.json |
| `subscription_renewal` | https://revcent.com/documentation/files/function/event/filter/subscription_renewal.json |
| `trial` | https://revcent.com/documentation/files/function/event/filter/trial.json |

Common filter Function paths:

```javascript
event.data.item_type
event.data.item_id
event.data.item_details
```

Because notations are not present, do not rely on:

```javascript
event.data.event_notations
```

unless the specific payload explicitly contains it.

### Filter Function Return Value

When an `api_direct` Function is used as a filter Function for AI Assistants or AI Voice Agents, it should return a single term:

```javascript
return "pass";
```

or:

```javascript
return "fail";
```

Meaning:

- `pass`: allow the AI Assistant or AI Voice Agent to proceed.
- `fail`: prevent the AI Assistant or AI Voice Agent from proceeding for that item.

### Typical Use Cases

- AI tool execution.
- Manual API-triggered workflows.
- Payload transformation.
- External system orchestration.
- On-demand reporting.
- AI Assistant filtering.
- AI Voice Agent filtering.
- Item-specific eligibility checks before an AI run or call.

### Best Practices

- Define clear `custom_arguments` for normal API-direct triggering.
- Validate every expected argument.
- Fail clearly when arguments are missing.
- Do not assume item context exists unless supplied.
- For filter usage, use the filter event body URL matching the `item_type`.
- For filter usage, do not include or rely on `custom_arguments`.
- For filter usage, return only `"pass"` or `"fail"`.
- For filter usage, do not rely on account-event notations.

---

## `payment_profile`

### Event Body JSON

https://revcent.com/documentation/files/function/event/payment_profile.json

### Applies To

`payment_profile` Functions run from a **Run Function** action node inside a Next-Gen Payment Profile flow.

KB reference:

https://kb.revcent.com/payments/credit-card/next-gen-payment-profile#run-function

A Run Function node can operate in two different run methods:

| Run Method | Behavior |
|---|---|
| `Queue And Continue` | The Function runs separately. RevCent does not wait for a response. The payment flow continues through the green output of the Run Function node. |
| `Wait For Response` | RevCent waits for the Function response. The response can determine the next node, output path, gateway choice, or custom error. |

Important warnings for `Wait For Response`:

- Route the red output as a backup in case the Function fails or times out.
- The Function has a maximum of 8 seconds to respond within the flow.
- Bad Function code can prevent payments from being processed.
- Functions add latency to the payment response.
- Use this only when you fully understand the Next-Gen payment flow.

---

### Runtime Event Structure

Payment-profile Functions receive the current payment flow request in `event.data`.

The item details of the payment request are contained in:

```javascript
event.data.item_details
```

Top-level event paths:

```javascript
event.data.item_type
event.data.item_id
event.data.item_event
event.data.item_details
```

Common payment-profile paths:

```javascript
event.data.item_details.request
event.data.item_details.entity
event.data.item_details.customer
event.data.item_details.customer_card
event.data.item_details.campaign
event.data.item_details.payment_profile
event.data.item_details.payment_amount
event.data.item_details.products
event.data.item_details.shipping
event.data.item_details.tax
event.data.item_details.gateway_history
event.data.item_details.node_id
event.data.item_details.next_nodes
event.data.item_details.current_step
event.data.item_details.step_array
event.data.item_details.flow_path
```

### Event Body Key Fields

| Field | Type | Description |
|---|---:|---|
| `event.data.item_type` | string | The item type being processed, such as `sale`. |
| `event.data.item_id` | string | The item ID being processed. |
| `event.data.item_event` | string | The event for the payment flow request, such as `payment_request`. |
| `event.data.item_details.request` | object | Details about the payment request. For initial sale requests, this can include metadata sent in the API call. |
| `event.data.item_details.entity` | object | The entity related to the request. For an initial sale this is the sale; for subscription renewal this relates to the subscription and may include a subscription renewal sub-item. |
| `event.data.item_details.customer` | object | Customer details related to the request. |
| `event.data.item_details.customer_card` | object | Customer card details related to the request, including card type, first 6, and BIN details when available. |
| `event.data.item_details.campaign` | object | Campaign details related to the request. |
| `event.data.item_details.payment_profile` | object | Payment Profile details related to the request. |
| `event.data.item_details.payment_amount` | number | The amount being processed by the flow request. |
| `event.data.item_details.products` | array | Product objects specific to the payment flow request. |
| `event.data.item_details.shipping` | array | Shipping objects specific to the payment flow request. |
| `event.data.item_details.tax` | array | Tax objects specific to the payment flow request. |
| `event.data.item_details.gateway_history` | object | Gateway and gateway-group history for the current request, customer, entity, and gateway group. |
| `event.data.item_details.node_id` | string | The current Run Function node ID. |
| `event.data.item_details.next_nodes` | object | Nodes connected to the Run Function node outputs. Useful when returning `next_node_id`. |
| `event.data.item_details.current_step` | integer | The current payment flow step being processed. |
| `event.data.item_details.step_array` | array | Current and previous payment attempt steps. Useful for deciding what to do after declines. |
| `event.data.item_details.flow_path` | array | Ordered list of nodes processed so far and their results. |

### Gateway History

`gateway_history` is especially important for routing logic.

Common paths:

```javascript
event.data.item_details.gateway_history.current.declined
event.data.item_details.gateway_history.customer.approved
event.data.item_details.gateway_history.customer.approved_cvv
event.data.item_details.gateway_history.customer.declined
event.data.item_details.gateway_history.customer.declined_cvv
event.data.item_details.gateway_history.entity.approved
event.data.item_details.gateway_history.entity.approved_cvv
event.data.item_details.gateway_history.entity.declined
event.data.item_details.gateway_history.entity.declined_cvv
event.data.item_details.gateway_history.gateway_group.approved
event.data.item_details.gateway_history.gateway_group.approved_cvv
event.data.item_details.gateway_history.gateway_group.declined
event.data.item_details.gateway_history.gateway_group.declined_cvv
```

Use this data to decide:

- Whether to retry a gateway.
- Whether to avoid a gateway.
- Whether to choose a gateway group.
- Whether the customer or entity has prior approvals or declines.
- Whether CVV-passed history should influence routing.

---

## Payment Profile Function Response

If the Run Function node is configured with `Queue And Continue`, the Function response is not used to control the payment flow.

If the Run Function node is configured with `Wait For Response`, the Function should return a response object using:

```javascript
return {
  // response properties here
};
```

If no properties are returned, RevCent treats the Run Function node as passed and follows the green output without taking additional action.

Only return the properties needed for the desired action.

### Response Object Shape

```javascript
return {
  next_node_id: "43965f05-887a-4e70-8646-0410440a3494",
  next_output: "1",
  set_gateway_id: "bOLjn0yvKpUp10qK298R",
  selection_method: "evenly_distribute",
  choose_gateways: ["2r7zOBMldVIomKNdKZoG"],
  choose_gateway_groups: ["GOGaPRql9oUAAkrm5Ll9"],
  custom_error: "Card CVV Invalid"
};
```

### Response Fields

| Field | Type | Description |
|---|---:|---|
| `next_node_id` | string | Routes to a specific next node connected to the Run Function node output. Use `event.data.item_details.next_nodes.actions` or `event.data.item_details.next_nodes.filters` to determine available nodes. |
| `next_output` | string | Chooses the Run Function node output path. `1` is green output; `2` is red output. |
| `set_gateway_id` | string | Sets a specific gateway as the current step gateway for payment processing. A Process Payment node must be in the output path for payment to process. |
| `selection_method` | string | Overrides the next Choose Gateway node's selection method when used with `choose_gateways` or `choose_gateway_groups`. Common values include `evenly_distribute`, `round_robin`, and `random`. |
| `choose_gateways` | array<string> | Overrides a next Choose Gateway node's gateway selections with the provided gateway IDs. |
| `choose_gateway_groups` | array<string> | Overrides a next Choose Gateway node's gateway group selections with the provided gateway group IDs. |
| `custom_error` | string | Provides a custom error response for a following Abort Flow node. Must also return a `next_node_id` pointing to an Abort Flow node. |

### Response Examples

#### Pass Through Green Output

```javascript
return {};
```

or:

```javascript
return {
  next_output: "1"
};
```

#### Route Through Red Output

```javascript
return {
  next_output: "2"
};
```

#### Route to a Specific Node

```javascript
return {
  next_node_id: "43965f05-887a-4e70-8646-0410440a3494"
};
```

#### Set a Gateway and Route to Process Payment

```javascript
return {
  set_gateway_id: "bOLjn0yvKpUp10qK298R",
  next_node_id: "f96f16ba-2cab-4ae5-9932-4f548cd479ba"
};
```

#### Override Gateway Choices

```javascript
return {
  selection_method: "random",
  choose_gateways: ["2r7zOBMldVIomKNdKZoG"],
  next_node_id: "43965f05-887a-4e70-8646-0410440a3494"
};
```

#### Abort with a Custom Error

```javascript
return {
  next_node_id: "0b8a520e-a74e-4516-8a5b-807337687847",
  custom_error: "Card CVV Invalid"
};
```

Important:

- The `next_node_id` should point to a following Abort Flow node when using `custom_error`.
- The shopping cart or API client must be able to parse and display custom errors correctly.
- Custom error behavior depends on whether payment was attempted.

### Typical Use Cases

- Payment routing.
- Gateway decisioning.
- Fraud checks.
- Payment orchestration.
- Custom decline handling.
- Gateway response parsing.
- Custom transaction logic.
- Custom payment error messages.
- Routing after failed gateway attempts.
- Choosing gateways based on customer, entity, or gateway history.

### Best Practices

- Keep execution fast because payment flows are time-sensitive.
- For `Wait For Response`, always design for the 8-second timeout.
- Always connect the red output to a safe fallback route.
- Validate customer, card, gateway, and payment objects before use.
- Avoid long-running external requests.
- Use environment variables for secrets.
- Handle retry-safe logic carefully.
- Return only the response properties needed.
- Use `Queue And Continue` if the Function does not need to control the flow.
- Use `Wait For Response` only when the Function response must determine the next action.

---

## `function_url`

### Event Body JSON

https://revcent.com/documentation/files/function/event/function_url.json

### Runtime Event Structure

Function URL triggers receive inbound request data.

Example payload:

```json
{
  "data": "{\"test\": \"urltest\"}"
}
```

### Typical Use Cases

- Partner integrations.
- Lightweight inbound APIs.
- Form receivers.
- External callbacks.
- Internal utility endpoints.

### Best Practices

- Validate inbound payloads.
- Authenticate requests where possible.
- Use IP restriction when appropriate.
- Expect arbitrary user input.

---

## `webhook`

### Event Body JSON

https://revcent.com/documentation/files/function/event/webhook.json

### Runtime Event Structure

Webhook triggers receive POST request data.

Example payload:

```json
{
  "data": "{\"test\": \"webhooktest\"}"
}
```

### Typical Use Cases

- External webhook ingestion.
- Third-party notifications.
- Partner callback processing.
- Event-forwarding systems.

### Best Practices

- Verify signatures or secrets when possible.
- Prevent duplicate processing.
- Return fast responses.
- Store important payloads safely.

---

## `schedule`

### Event Body JSON

https://revcent.com/documentation/files/function/event/schedule.json

### Runtime Event Structure

Scheduled Functions typically receive a minimal payload.

Example:

```json
{
  "data": ""
}
```

### Typical Use Cases

- Daily reports.
- Scheduled cleanup.
- Batch synchronization.
- Periodic API syncs.
- Maintenance jobs.

### Best Practices

- Build idempotent jobs.
- Handle empty payloads.
- Avoid assuming only one execution can occur at a time.
- Log execution checkpoints where appropriate.

---

## `pre_agent`

### Event Body JSON

https://revcent.com/documentation/files/function/event/pre_agent.json

### Applies To

`pre_agent` Functions are specifically for **AI Voice Agents**. They run immediately before an AI Voice Agent is initiated for a call.

The purpose of a pre-agent Function is to generate custom data that can be used inside AI Voice Agent instructions with Handlebars.

KB reference:

https://kb.revcent.com/en/tools/ai/voice-agents#pre-agent-function

### Runtime Event Structure

A pre-agent Function receives the item details related to the call, plus call/agent context.

Common paths include:

```javascript
event.data.item_type
event.data.item_id
event.data.item_details
```

The provided example payload contains a full Customer object in `event.data.item_details`.

Pre-agent Functions may run for different AI Voice Agent call scenarios:

| AI Voice Agent scenario | Event body behavior |
|---|---|
| Inbound call with customer phone match | Receives customer item context. |
| Inbound call without customer phone match | May receive an empty object. |
| Outbound call from event trigger | Receives event notation plus item context, such as sale/customer/shipping data. |
| Outbound call from on-demand trigger | Receives the supplied item type, item ID, and populated item details. |

### Return Value and Handlebars Usage

The pre-agent Function should return or complete with a plain JSON object.

Example Function code:

```javascript
exports.handler = async function(event, context) {
  return {
    company_name: "Acme Inc.",
    allow_full_refunds: false,
    product_list: [
      {
        name: "Product A",
        price: 29.99
      }
    ]
  };
};
```

The response is made available to AI Voice Agent instruction Handlebars under:

```handlebars
{{pre_agent_function.response.company_name}}
{{pre_agent_function.response.allow_full_refunds}}
{{{toString pre_agent_function.response.product_list}}}
```

## AI Voice Agent Pre-Agent Function Response Object

The AI Voice Agent instructions Handlebars data includes a `pre_agent_function` object when a pre-agent Function is configured.

Response object shape:

```json
{
  "pre_agent_function": {
    "has_response": true,
    "response": {
      "company_name": "Acme Inc.",
      "allow_full_refunds": false
    }
  }
}
```

### `pre_agent_function.has_response`

**Type:** `boolean`

Indicates whether a pre-agent Function ran and returned a valid JSON object.

Use this when instructions should only reference response fields if the Function returned data.

```handlebars
{{#if pre_agent_function.has_response}}
Use the pre-agent function response below.
{{else}}
No pre-agent function response is available.
{{/if}}
```

### `pre_agent_function.response`

**Type:** `object`

The plain JSON object returned by the pre-agent Function.

Example Function body:

```javascript
return {
  company_name: "Acme Inc.",
  allow_full_refunds: false,
  product_list: [
    {
      name: "Product A",
      price: 29.99
    }
  ]
};
```

Example AI Voice Agent instruction usage:

```handlebars
{{#if pre_agent_function.response.company_name}}
- Identify as {{pre_agent_function.response.company_name}} customer support.
{{else}}
- Identify as customer support.
{{/if}}
```

For JSON objects or arrays, use the `toString` helper with triple braces:

```handlebars
# Available Products
{{{toString pre_agent_function.response.product_list}}}
```

Important:

- The Function should return a plain JSON object.
- The object is not inserted directly at the root of Handlebars data.
- It is available under `pre_agent_function.response`.
- Use stable key names because AI Voice Agent instructions reference these keys.
- Do not return sensitive secrets into the response object because the response may be included in AI instructions.

### Typical Use Cases

- Generate dynamic company or brand names for outbound calls.
- Build product lists to embed into voice-agent instructions.
- Add campaign-specific instructions.
- Add refund, escalation, or compliance rules.
- Enrich call instructions with external CRM data.
- Customize greetings or call objectives based on the call item.
- Provide structured JSON to the voice agent using the `toString` Handlebars helper.

### Best Practices

- Return a plain JSON object.
- Keep preprocessing fast so the voice call can start quickly.
- Validate nested item/customer properties before use.
- Handle inbound calls with no customer match.
- Do not return sensitive secrets into the instruction context.
- Avoid excessive external requests before agent execution.
- Use stable keys because AI Voice Agent instructions will reference them with Handlebars.

---

## `email_template`

### Event Body Relationship

Email-template Functions do not use a dedicated Function event-body file. Instead, they receive the same item context used by the Email Template trigger.

The related item details are commonly available at:

```javascript
event.data.item_details
```

The exact payload shape depends on the Email Template trigger.

Examples:

| Email Template Trigger | Source Input Data JSON |
|---|---|
| `sale_create_success` | https://revcent.com/documentation/files/email_template/input_data/sale.json |
| `customer_create_success` | https://revcent.com/documentation/files/email_template/input_data/customer.json |
| `subscription_renew_success` | https://revcent.com/documentation/files/email_template/input_data/subscription_renewal.json |

### Typical Use Cases

- Dynamic email personalization.
- Custom receipt content.
- AI-generated email snippets.
- Conditional email sections.
- External data enrichment for emails.

### Best Practices

- Return a plain JavaScript object.
- Keep payloads lightweight.
- Avoid circular references.
- Validate required nested paths before use.



# Event Source Reference

| `event_source` | Trigger behavior | Related fields |
|---|---|---|
| `account_event` | RevCent triggers the Function automatically when configured account events occur. | `account_event_notations`, `account_event_filters`, `timing_options` |
| `api_direct` | Function can be triggered via API/MCP or AI System Tool. It can also be used as a filter Function for AI Assistants and AI Voice Agents; filter payloads use `https://revcent.com/documentation/files/function/event/filter/<item_type>.json`. | `custom_arguments` only for direct triggering. Do not include `custom_arguments` for filter Function usage; filter usage uses item context and should return `pass` or `fail`. |
| `email_template` | Function generates `custom_data` for an Email Template. | `function_code`, environment/dependencies as needed |
| `payment_profile` | Function runs during Next-Gen payment profile processing. Event body: [`payment_profile.json`](https://revcent.com/documentation/files/function/event/payment_profile.json). | `function_code`, environment/dependencies as needed |
| `function_url` | Function is triggered by HTTP GET or POST request. | `ip_restricted`, `ip_whitelist` |
| `schedule` | Function runs on a fixed schedule using a cron expression. | `cron_expression`, `cron_timezone` |

---

## `account_event_notations`

**Type:** `array<string>`  
**Required:** No  
**Applies when:** `event_source` is `account_event`

Specifies one or more account event notations that trigger the Function.

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "event_source": "account_event",
  "account_event_notations": ["sale.created.success", "chargeback.created"]
}
```

When one of the configured account events occurs, RevCent triggers the Function.

For account event Functions, the event body JSON link is determined by the first word in the notation. For example, `sale.created` uses the `sale` account-event body file:

```text
https://revcent.com/documentation/files/function/event/account_event/sale.json
```

### Allowed Account Event Notations

```text
ai_memo.created
chargeback.created
check_direct.created
customer.created
customer.updated.add_card
customer.updated.address
customer.updated.customer_group
customer.updated.customer_group.added
customer.updated.customer_group.removed
customer.updated.disabled
customer.updated.enabled
discount.created
fraud_detection.created
fraud_detection.updated.false_positive
invoice.created
note.created
offline_payment.created
paypal_dispute.created
paypal_transaction.created
pending_refund.created
pending_refund.created.product_sale
pending_refund.created.product_sale.full
pending_refund.created.product_sale.partial
pending_refund.created.shipping
pending_refund.created.shipping.full
pending_refund.created.shipping.full.has_fulfillment
pending_refund.created.shipping.full.no_fulfillment
pending_refund.created.shipping.has_fulfillment
pending_refund.created.shipping.no_fulfillment
pending_refund.created.shipping.partial
pending_refund.created.shipping.partial.has_fulfillment
pending_refund.created.shipping.partial.no_fulfillment
pending_refund.created.subscription_renewal
pending_refund.created.subscription_renewal.full
pending_refund.created.subscription_renewal.partial
pending_refund.created.tax
pending_refund.created.tax.full
pending_refund.created.tax.partial
product.created
product.deleted
product.updated
product_sale.created
sale.created
sale.created.failed
sale.created.failed.declined
sale.created.failed.error
sale.created.failed.no_gateway
sale.created.failed.fraud_detected
sale.created.failed.merchant_error
sale.created.failed.merchant_hold
sale.created.success
sale.created.success.has_salvage
sale.created.success.is_upsell
sale.created.success.paid
sale.created.success.paid.has_salvage
sale.created.success.paid.is_upsell
sale.created.success.pending
sale.created.success.pending.is_upsell
sale.updated.fraud_alert.added
sale.updated.fraud_alert.removed
salvage_transaction.created
salvage_transaction.updated.processed
salvage_transaction.updated.processed.failed
salvage_transaction.updated.processed.success
sentinel.alert
sentinel.alert.fraud_detected
sentinel.alert.firewall_block
shipping.created
shipping.created.has_fulfillment
shipping.created.no_fulfillment
shipping.updated.delivered
shipping.updated.ship_to
shipping.updated.shipped
subscription.created
subscription.updated.renewed
subscription.updated.renewed.failed
subscription.updated.renewed.success
subscription.updated.status
subscription.updated.status.active
subscription.updated.status.cancelled
subscription.updated.status.occurrence_limit
subscription.updated.status.overdue
subscription.updated.status.suspended
subscription_renewal.updated.failed
subscription_renewal.updated.success
tax.created
transaction.created
trial.created
trial.updated.cancelled
trial.updated.expired
trial.updated.expired.failed
trial.updated.expired.success
trial.updated.extended
trial.updated.shortened
```


### Account Event Event JSON Links

Each account event notation maps to an account-event JSON body file based on the first word in the notation.

Pattern:

```text
https://revcent.com/documentation/files/function/event/account_event/<item_type>.json
```

Examples:

| Notation | First word / item type | Event JSON |
|---|---|---|
| `sale.created` | `sale` | [`sale.json`](https://revcent.com/documentation/files/function/event/account_event/sale.json) |
| `customer.created` | `customer` | [`customer.json`](https://revcent.com/documentation/files/function/event/account_event/customer.json) |
| `shipping.updated.shipped` | `shipping` | [`shipping.json`](https://revcent.com/documentation/files/function/event/account_event/shipping.json) |
| `subscription_renewal.updated.success` | `subscription_renewal` | [`subscription_renewal.json`](https://revcent.com/documentation/files/function/event/account_event/subscription_renewal.json) |

Use the linked JSON file as the source of truth for the `event` payload body when writing `function_code` for `account_event` Functions.

| Account event item type | Event JSON | Notations that use this event body |
|---|---|---|
| `ai_memo` | [`ai_memo.json`](https://revcent.com/documentation/files/function/event/account_event/ai_memo.json) | `ai_memo.created` |
| `chargeback` | [`chargeback.json`](https://revcent.com/documentation/files/function/event/account_event/chargeback.json) | `chargeback.created` |
| `check_direct` | [`check_direct.json`](https://revcent.com/documentation/files/function/event/account_event/check_direct.json) | `check_direct.created` |
| `customer` | [`customer.json`](https://revcent.com/documentation/files/function/event/account_event/customer.json) | `customer.created`, `customer.updated.add_card`, `customer.updated.address`, `customer.updated.customer_group`, `customer.updated.customer_group.added`, `customer.updated.customer_group.removed`, `customer.updated.disabled`, `customer.updated.enabled` |
| `discount` | [`discount.json`](https://revcent.com/documentation/files/function/event/account_event/discount.json) | `discount.created` |
| `fraud_detection` | [`fraud_detection.json`](https://revcent.com/documentation/files/function/event/account_event/fraud_detection.json) | `fraud_detection.created`, `fraud_detection.updated.false_positive` |
| `invoice` | [`invoice.json`](https://revcent.com/documentation/files/function/event/account_event/invoice.json) | `invoice.created` |
| `note` | [`note.json`](https://revcent.com/documentation/files/function/event/account_event/note.json) | `note.created` |
| `offline_payment` | [`offline_payment.json`](https://revcent.com/documentation/files/function/event/account_event/offline_payment.json) | `offline_payment.created` |
| `paypal_dispute` | [`paypal_dispute.json`](https://revcent.com/documentation/files/function/event/account_event/paypal_dispute.json) | `paypal_dispute.created` |
| `paypal_transaction` | [`paypal_transaction.json`](https://revcent.com/documentation/files/function/event/account_event/paypal_transaction.json) | `paypal_transaction.created` |
| `pending_refund` | [`pending_refund.json`](https://revcent.com/documentation/files/function/event/account_event/pending_refund.json) | `pending_refund.created`, `pending_refund.created.product_sale`, `pending_refund.created.product_sale.full`, `pending_refund.created.product_sale.partial`, `pending_refund.created.shipping`, `pending_refund.created.shipping.full`, `pending_refund.created.shipping.full.has_fulfillment`, `pending_refund.created.shipping.full.no_fulfillment`, `pending_refund.created.shipping.has_fulfillment`, `pending_refund.created.shipping.no_fulfillment`, `pending_refund.created.shipping.partial`, `pending_refund.created.shipping.partial.has_fulfillment`, `pending_refund.created.shipping.partial.no_fulfillment`, `pending_refund.created.subscription_renewal`, `pending_refund.created.subscription_renewal.full`, `pending_refund.created.subscription_renewal.partial`, `pending_refund.created.tax`, `pending_refund.created.tax.full`, `pending_refund.created.tax.partial` |
| `product` | [`product.json`](https://revcent.com/documentation/files/function/event/account_event/product.json) | `product.created`, `product.deleted`, `product.updated` |
| `product_sale` | [`product_sale.json`](https://revcent.com/documentation/files/function/event/account_event/product_sale.json) | `product_sale.created` |
| `sale` | [`sale.json`](https://revcent.com/documentation/files/function/event/account_event/sale.json) | `sale.created`, `sale.created.failed`, `sale.created.failed.declined`, `sale.created.failed.error`, `sale.created.failed.no_gateway`, `sale.created.failed.fraud_detected`, `sale.created.failed.merchant_error`, `sale.created.failed.merchant_hold`, `sale.created.success`, `sale.created.success.has_salvage`, `sale.created.success.is_upsell`, `sale.created.success.paid`, `sale.created.success.paid.has_salvage`, `sale.created.success.paid.is_upsell`, `sale.created.success.pending`, `sale.created.success.pending.is_upsell`, `sale.updated.fraud_alert.added`, `sale.updated.fraud_alert.removed` |
| `salvage_transaction` | [`salvage_transaction.json`](https://revcent.com/documentation/files/function/event/account_event/salvage_transaction.json) | `salvage_transaction.created`, `salvage_transaction.updated.processed`, `salvage_transaction.updated.processed.failed`, `salvage_transaction.updated.processed.success` |
| `sentinel` | [`sentinel.json`](https://revcent.com/documentation/files/function/event/account_event/sentinel.json) | `sentinel.alert`, `sentinel.alert.fraud_detected`, `sentinel.alert.firewall_block` |
| `shipping` | [`shipping.json`](https://revcent.com/documentation/files/function/event/account_event/shipping.json) | `shipping.created`, `shipping.created.has_fulfillment`, `shipping.created.no_fulfillment`, `shipping.updated.delivered`, `shipping.updated.ship_to`, `shipping.updated.shipped` |
| `subscription` | [`subscription.json`](https://revcent.com/documentation/files/function/event/account_event/subscription.json) | `subscription.created`, `subscription.updated.renewed`, `subscription.updated.renewed.failed`, `subscription.updated.renewed.success`, `subscription.updated.status`, `subscription.updated.status.active`, `subscription.updated.status.cancelled`, `subscription.updated.status.occurrence_limit`, `subscription.updated.status.overdue`, `subscription.updated.status.suspended` |
| `subscription_renewal` | [`subscription_renewal.json`](https://revcent.com/documentation/files/function/event/account_event/subscription_renewal.json) | `subscription_renewal.updated.failed`, `subscription_renewal.updated.success` |
| `tax` | [`tax.json`](https://revcent.com/documentation/files/function/event/account_event/tax.json) | `tax.created` |
| `transaction` | [`transaction.json`](https://revcent.com/documentation/files/function/event/account_event/transaction.json) | `transaction.created` |
| `trial` | [`trial.json`](https://revcent.com/documentation/files/function/event/account_event/trial.json) | `trial.created`, `trial.updated.cancelled`, `trial.updated.expired`, `trial.updated.expired.failed`, `trial.updated.expired.success`, `trial.updated.extended`, `trial.updated.shortened` |



Best practices:

- Use the most specific notation available.
- For example, prefer `sale.created.success.paid` if the Function should only run for paid successful sales.
- Use broader notations like `sale.created` only if the Function should handle all sale outcomes.
- Confirm the event data shape for each notation before writing code.

---

## `account_event_filters`

**Type:** `object`  
**Required:** No  
**Applies when:** `event_source` is `account_event`

Filters account events to determine whether the Function should run.

Schema:

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "account_event_filters": {
    "campaign_filter": ["XXXXXXXXXXXXXXXXXXXX"]
  }
}
```

### `account_event_filters.campaign_filter`

**Type:** `array<string>`

A list of 20-character Campaign IDs.

Behavior:

- The Function only triggers when the account event is related to one of the listed campaigns.
- The related event must contain campaign context for the filter to apply.
- Omit `account_event_filters` if no filter should be changed.

---

## `timing_options`

**Type:** `object`  
**Required:** No  
**Applies when:** `event_source` is `account_event`

Determines when the Function runs after being triggered by an account event.

If not provided, the Function runs immediately after being triggered.

Schema:

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "timing_options": {
    "timing": "delay",
    "time_unit": "hours",
    "time_value": 2
  }
}
```

### `timing_options.timing`

**Type:** `string` enum

Allowed values:

```text
immediate
delay
```

Behavior:

- `immediate`: run immediately when the account event occurs.
- `delay`: run after the configured delay.

### `timing_options.time_unit`

**Type:** `string` enum

Allowed values:

```text
minutes
hours
```

Required if `timing` is `delay`.

### `timing_options.time_value`

**Type:** `integer`

The numeric delay amount.

Required if `timing` is `delay`.

Example:

```json
{
  "timing": "delay",
  "time_unit": "hours",
  "time_value": 2
}
```

This runs the Function 2 hours after the account event occurs.

---

## `cron_expression`

**Type:** `string`  
**Required:** No  
**Applies when:** `event_source` is `schedule`

The cron expression that determines when the Function runs.

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "event_source": "schedule",
  "cron_expression": "0 9 * * *",
  "cron_timezone": "America/New_York"
}
```

Requirements:

- Must be a valid 5-part cron expression.
- Applies only to scheduled Functions.
- Pair with `cron_timezone` when schedule timing should be interpreted in a specific timezone.

Example 5-part cron:

```text
0 9 * * *
```

Meaning: every day at 9:00 AM in the configured timezone.

---

## `cron_timezone`

**Type:** `string`  
**Required:** No  
**Applies when:** `event_source` is `schedule`

The timezone for the cron expression.

```json
"cron_timezone": "America/New_York"
```

Behavior:

- Must be a valid IANA timezone string.
- If omitted, UTC is used.

Examples:

```text
UTC
America/New_York
America/Los_Angeles
Europe/London
```

---

# Dependencies

## `dependencies`

**Type:** `array<object>`  
**Required:** No

A list of dependencies required by the Function.

Important behavior:

- Any dependency may be used if it can be installed successfully.
- Use a valid package name and version.
- `"latest"` is allowed.
- If a dependency name or version cannot be installed, the Function cannot be provisioned successfully and will error.
- Dependencies are loaded in Function code with CommonJS `require()`.
- Do not use ESM `import` syntax.
- Modifying dependencies triggers redeployment and may take up to 5 minutes to return to `status: "READY"`.
- Use `GetFunction` and long poll deployment `status` after dependency updates.
- If you provide the `dependencies` array, any existing dependencies are replaced with the submitted list.
- To preserve previous dependencies, call `GetFunction` first, copy the existing dependencies, and include them in the edit request.

Example:

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "dependencies": [
    {
      "name": "axios",
      "version": "1.6.0"
    },
    {
      "name": "lodash",
      "version": "4.17.21"
    }
  ]
}
```

Function code usage:

```javascript
const axios = require("axios");
const lodash = require("lodash");
```

### `dependencies[].name`

**Type:** `string`

The dependency package name.

### `dependencies[].version`

**Type:** `string`

The dependency version.

Important:

- Ensure the version exists and is valid.
- `"latest"` is allowed.
- Invalid names or versions can prevent provisioning.

---

# Environment Variables

## `environment_variables`

**Type:** `array<object>`  
**Required:** No

A list of environment variables available to the Function when triggered.

Environment variables are accessed with:

```javascript
process.env["<env_variable_name>"]
```

Example:

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "environment_variables": [
    {
      "name": "SLACK_BOT_TOKEN",
      "value": "xoxb-example"
    },
    {
      "name": "SLACK_CHANNEL_ID",
      "value": "C1234567890"
    }
  ]
}
```

Function code usage:

```javascript
const token = process.env["SLACK_BOT_TOKEN"];
const channel = process.env["SLACK_CHANNEL_ID"];
```

Important behavior:

- Encrypted environment variables are decrypted and provided when the Function is triggered.
- When retrieving Function details via the API, encrypted environment variable values are hidden and not provided.
- This allows sensitive values such as API keys to be used by the Function without exposing them in retrieval responses.
- When editing a Function, providing `environment_variables` upserts variables.
- Existing variables are left intact.
- New variables are added/encrypted.
- Matching variable names have their values replaced.
- Providing `environment_variables` does not overwrite all existing environment variables.

### `environment_variables[].name`

**Type:** `string`

The environment variable name.

### `environment_variables[].value`

**Type:** `string`

The environment variable value.

Best practices:

- Use clear uppercase names, such as `SLACK_BOT_TOKEN`.
- Do not hardcode secrets in `function_code`.
- Only include `environment_variables` when adding or updating variables.

---


---

# Function URL / Webhook Security

## `ip_restricted`

**Type:** `boolean`  
**Required:** No  
**Applies when:** `event_source` is `function_url` or webhook-style usage

Whether the Function is IP restricted.

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "ip_restricted": true
}
```

Behavior:

- If `true`, only allowed IP addresses can trigger the Function.
- Only applies to Functions with `event_source` set to `function_url` or webhook-style external triggering.
- Use this for partner integrations or public endpoints whenever possible.

---

## `ip_whitelist`

**Type:** `array<string>`  
**Required:** No  
**Applies when:** `ip_restricted` is `true`

The list of allowed IPv4 addresses.

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "ip_restricted": true,
  "ip_whitelist": ["203.0.113.10", "198.51.100.25"]
}
```

Requirements:

- Each entry should be a valid IPv4 address.
- IP ranges are not supported.
- CIDR notation is not supported by the schema description.
- Only exact IPv4 addresses should be provided.

---

# API / AI Custom Arguments

## `custom_arguments`

**Type:** `array<object>`  
**Required:** No  
**Applies only when:** `event_source` is `api_direct` **and the Function is not being used as a filter Function**

Defines custom arguments that should be provided when triggering the Function using `TriggerFunction`.

Important behavior:

- Only include `custom_arguments` for normal API/MCP or AI tool-triggered `api_direct` Functions.
- Do not include `custom_arguments` when the `api_direct` Function is being used as a filter Function for AI Assistants or AI Voice Agents.
- Filter Functions receive their input from the item context event body, based on `item_type` and `item_id`.
- Filter Function event bodies use the pattern `https://revcent.com/documentation/files/function/event/filter/<item_type>.json`.
- Custom arguments are intended to be used by AI to infer values when directly triggering the Function.
- If `custom_arguments` is provided, any existing custom arguments are replaced with the submitted list.
- To preserve previous custom arguments, call `GetFunction` first and include existing arguments in the edit request.
- Custom argument names should contain letters and underscores only, with no spaces.

Example:

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "event_source": "api_direct",
  "custom_arguments": [
    {
      "name": "sale_id",
      "description": "The 20-character sale ID to process."
    },
    {
      "name": "summary_reason",
      "description": "A short explanation of why this function is being triggered."
    }
  ]
}
```

### `custom_arguments[].name`

**Type:** `string`

The custom argument name.

Rules:

- Letters and underscores only.
- No spaces.

### `custom_arguments[].description`

**Type:** `string`

The description used to determine what value should be provided when the Function is triggered.

Good description:

```text
The 20-character sale ID for the sale that should be summarized.
```

Poor description:

```text
sale
```

Function code should read the runtime argument format according to the trigger payload supplied by `TriggerFunction`.

---

# Event Source Setup Examples

## Account Event Function

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "enabled": true,
  "event_source": "account_event",
  "account_event_notations": ["sale.created.success.paid"],
  "account_event_filters": {
    "campaign_filter": ["YYYYYYYYYYYYYYYYYYYY"]
  },
  "timing_options": {
    "timing": "immediate"
  }
}
```

Use when the Function should run automatically when a matching RevCent account event occurs.

---

## Delayed Account Event Function

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "event_source": "account_event",
  "account_event_notations": ["sale.created.success"],
  "timing_options": {
    "timing": "delay",
    "time_unit": "hours",
    "time_value": 2
  }
}
```

Use when the Function should run after a delay.

---

## Scheduled Function

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "enabled": true,
  "event_source": "schedule",
  "cron_expression": "0 9 * * *",
  "cron_timezone": "America/New_York"
}
```

Use when the Function should run on a fixed schedule.

---

## API / AI Direct Function

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "enabled": true,
  "event_source": "api_direct",
  "custom_arguments": [
    {
      "name": "customer_email",
      "description": "The customer's email address."
    },
    {
      "name": "message_body",
      "description": "The message body to process."
    }
  ]
}
```

Use when the Function should be triggered by API/MCP or AI.

---

## API Direct Filter Function for AI Assistants or AI Voice Agents

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "enabled": true,
  "event_source": "api_direct",
  "function_code": "exports.handler = async function(event, context) { let item = event.data.item_details; if (item && item.enabled !== false) { return 'pass'; } return 'fail'; };"
}
```

Do not include `custom_arguments` for this filter Function configuration. The filter Function receives its input from the item context.

Use the filter event body for the item type being evaluated:

```text
https://revcent.com/documentation/files/function/event/filter/<item_type>.json
```

For example, a sale filter Function should reference:

```text
https://revcent.com/documentation/files/function/event/filter/sale.json
```

---

## Email Template Custom Data Function

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "enabled": true,
  "event_source": "email_template",
  "function_code": "exports.handler = async function(event, context) { let item = event.data.item_details; return { customer_email: item.customer.email }; };"
}
```

Use with an Email Template custom data configuration:

```json
{
  "custom_data": {
    "enabled": true,
    "source_type": "custom_function",
    "source_value": "XXXXXXXXXXXXXXXXXXXX"
  }
}
```

Where `source_value` is the Function ID.

---

## Function URL with IP Restriction

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "enabled": true,
  "event_source": "function_url",
  "ip_restricted": true,
  "ip_whitelist": ["203.0.113.10"]
}
```

Use for external HTTP-triggered integrations.

---

## Function with Dependencies and Environment Variables

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "dependencies": [
    {
      "name": "axios",
      "version": "1.6.0"
    }
  ],
  "environment_variables": [
    {
      "name": "PARTNER_API_KEY",
      "value": "example-secret"
    }
  ],
  "function_code": "const axios = require('axios'); exports.handler = async function(event, context) { const apiKey = process.env['PARTNER_API_KEY']; return { configured: Boolean(apiKey) }; };"
}
```

---

# Function Code Patterns

## Function Code Includes the Handler

Always include an outer handler declaration. RevCent does not add the handler automatically.

Correct:

```javascript
exports.handler = async function(event, context) {
  return {
    success: true
  };
};
```

## Minimal Success

```javascript
exports.handler = async function(event, context) {
  return {
    success: true
  };
};
```

## Minimal Error

```javascript
exports.handler = async function(event, context) {
  throw new Error("Something went wrong.");
};
```

## Safe Try/Catch

```javascript
exports.handler = async function(event, context) {
  try {
    return {
      success: true
    };
  } catch (error) {
    throw error;
  }
};
```

## Callback-Style Success

```javascript
exports.handler = async function(event, context, callback) {
  callback(null, {
    success: true
  });
};
```

## Callback-Style Error Handling

```javascript
exports.handler = async function(event, context, callback) {
  try {
    callback(null, {
      success: true
    });
  } catch (error) {
    callback(error);
  }
};
```

## Using a Dependency

```javascript
const axios = require("axios");

exports.handler = async function(event, context) {
  try {
    const response = await axios.post("https://example.com/webhook", {
      hello: "world"
    });

    return {
      status: response.status
    };
  } catch (error) {
    throw error;
  }
};
```

## Using Environment Variables

```javascript
exports.handler = async function(event, context) {
  const apiKey = process.env["PARTNER_API_KEY"];

  if (!apiKey) {
    throw new Error("Missing PARTNER_API_KEY.");
  }

  return {
    has_api_key: true
  };
};
```

## Returning Email Template Custom Data

```javascript
exports.handler = async function(event, context) {
  let item = event.data.item_details;

  return {
    first_name_uppercase: item.customer.first_name.toUpperCase(),
    support_email: "support@example.com"
  };
};
```

Email Template usage:

```handlebars
<p>Hello {{custom_data.first_name_uppercase}}</p>
<p>Need help? Email {{custom_data.support_email}}</p>
```

---

---

# Third-Party Integrations with Functions

RevCent Functions can be used to integrate with almost any third-party system because Function code can make outbound internet requests, use supported third-party dependencies, and securely access encrypted environment variables.

Use Functions when RevCent needs to:

- Send event data to a third-party system.
- Receive data from a third-party system.
- Transform RevCent data into an external API payload.
- Enrich RevCent events with external API data.
- Route payments based on external decisioning.
- Send Slack, SendGrid, Twilio, Mailchimp, CRM, fulfillment, analytics, or webhook requests.
- Build custom business logic that RevCent does not provide natively.

---

## Outbound Internet Access

Functions can make outbound internet requests to third-party APIs.

Typical use cases:

| Use Case | Example |
|---|---|
| Webhook forwarding | Send sale data to a partner endpoint. |
| CRM sync | Create or update a contact in an external CRM. |
| Slack notifications | Post account events to a Slack channel. |
| Email/SMS integrations | Send messages through SendGrid, Mailchimp, Twilio, or another provider. |
| Fulfillment integrations | Send shipping or product data to a warehouse or fulfillment provider. |
| Fraud/risk scoring | Call an external fraud service and return a pass/fail or routing decision. |
| Payment routing | Query an external decision engine before choosing a payment gateway. |
| AI integrations | Call OpenAI or another AI provider to generate summaries or structured output. |

Example using `axios`:

```javascript
const axios = require("axios");

exports.handler = async function(event, context) {
  try {
    const response = await axios.post(
      "https://api.example.com/events",
      {
        event_type: event.data.item_type,
        item_id: event.data.item_id,
        item_details: event.data.item_details
      },
      {
        headers: {
          Authorization: `Bearer ${process.env["PARTNER_API_KEY"]}`,
          "Content-Type": "application/json"
        },
        timeout: 5000
      }
    );

    return {
      success: true,
      status: response.status
    };
  } catch (error) {
    throw error;
  }
};
```

Important:

- Use timeouts for external requests.
- Handle API errors explicitly.
- Avoid long-running calls, especially inside `payment_profile` Functions.
- Do not assume a third-party API is always available.
- Build retry-safe and idempotent logic where possible.

---

## Dependencies

Functions can use any dependency that can be installed successfully. Add dependencies through the `dependencies` array in `EditFunction`.

Important behavior:

- Use valid package names and versions.
- `"latest"` is allowed.
- If a dependency name or version cannot be installed, the Function cannot be provisioned successfully and will error.
- Load dependencies with CommonJS `require()`.
- Do not use ESM `import` syntax.
- Use this pattern:

```javascript
const axios = require("axios");
const _ = require("lodash");
const moment = require("moment");
```

Example `EditFunction` dependency configuration:

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "dependencies": [
    {
      "name": "axios",
      "version": "1.6.0"
    },
    {
      "name": "lodash",
      "version": "4.17.21"
    }
  ]
}
```

### Dependency Update Behavior

When the `dependencies` array is provided:

- The submitted list replaces the existing dependency list.
- To preserve current dependencies, call `GetFunction` first and include existing dependencies in the edit request.
- Dependency updates trigger redeployment and may take up to 5 minutes to reach `READY`.
- Invalid dependency names or versions can cause `UPDATE_FAILED` or execution errors.
- Use `GetFunction` and long poll deployment `status` after dependency updates.


## Encrypted Environment Variables

Use `environment_variables` for secrets, tokens, API keys, webhook signing secrets, and other private values.

Environment variables are available in Function code using:

```javascript
process.env["VARIABLE_NAME"]
```

Example configuration:

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "environment_variables": [
    {
      "name": "PARTNER_API_KEY",
      "value": "example-secret"
    },
    {
      "name": "SLACK_BOT_TOKEN",
      "value": "xoxb-example"
    }
  ]
}
```

Example usage:

```javascript
exports.handler = async function(event, context) {
  const apiKey = process.env["PARTNER_API_KEY"];

  if (!apiKey) {
    throw new Error("Missing PARTNER_API_KEY.");
  }

  return {
    configured: true
  };
};
```

Important behavior:

- Environment variables are encrypted.
- Encrypted values are decrypted when the Function runs.
- When retrieving Function details via API, encrypted values are hidden and not returned.
- Providing `environment_variables` in `EditFunction` upserts variables.
- Existing variables are left intact when omitted.
- Matching variable names have their values replaced.
- New variable names are added and encrypted.
- Omitted variables are not removed by an upsert.

Best practices:

- Never hardcode secrets in `function_code`.
- Use uppercase names such as `SLACK_BOT_TOKEN`, `OPENAI_API_KEY`, or `PARTNER_WEBHOOK_SECRET`.
- Keep environment variables scoped to the Function that needs them.
- Rotate secrets periodically.
- Avoid returning secret values in Function responses.
- Avoid logging secret values.

---

## Integration Pattern: Send a Webhook to a Partner

Use this pattern for event forwarding.

```javascript
const axios = require("axios");

exports.handler = async function(event, context) {
  try {
    const partnerUrl = process.env["PARTNER_WEBHOOK_URL"];
    const apiKey = process.env["PARTNER_API_KEY"];

    if (!partnerUrl || !apiKey) {
      throw new Error("Missing partner webhook configuration.");
    }

    const payload = {
      item_type: event.data.item_type,
      item_id: event.data.item_id,
      item_details: event.data.item_details
    };

    const response = await axios.post(partnerUrl, payload, {
      headers: {
        Authorization: `Bearer ${apiKey}`,
        "Content-Type": "application/json"
      },
      timeout: 5000
    });

    return {
      success: true,
      partner_status: response.status
    };
  } catch (error) {
    throw error;
  }
};
```

Recommended dependencies:

```json
[
  {
    "name": "axios",
    "version": "1.6.0"
  }
]
```

Recommended environment variables:

```json
[
  {
    "name": "PARTNER_WEBHOOK_URL",
    "value": "https://partner.example.com/webhook"
  },
  {
    "name": "PARTNER_API_KEY",
    "value": "secret"
  }
]
```

---

## Integration Pattern: Post to Slack

Use this pattern for internal notifications.

```javascript
const { WebClient } = require("@slack/web-api");

exports.handler = async function(event, context) {
  try {
    const token = process.env["SLACK_BOT_TOKEN"];
    const channel = process.env["SLACK_CHANNEL_ID"];

    if (!token || !channel) {
      throw new Error("Missing Slack configuration.");
    }

    const slack = new WebClient(token);

    const itemType = event.data.item_type;
    const itemId = event.data.item_id;

    await slack.chat.postMessage({
      channel,
      text: `RevCent event received: ${itemType} ${itemId}`
    });

    return {
      success: true
    };
  } catch (error) {
    throw error;
  }
};
```

Recommended dependencies:

```json
[
  {
    "name": "@slack/web-api",
    "version": "6.12.0"
  }
]
```

Recommended environment variables:

```json
[
  {
    "name": "SLACK_BOT_TOKEN",
    "value": "xoxb-secret"
  },
  {
    "name": "SLACK_CHANNEL_ID",
    "value": "C1234567890"
  }
]
```

---

## Integration Pattern: Generate Data for an Email Template

Use this pattern when an Email Template uses a Function as a `custom_data` source.

```javascript
exports.handler = async function(event, context) {
  try {
    const item = event.data.item_details;

    return {
      customer_email_domain: item.customer.email.split("@")[1],
      support_email: process.env["SUPPORT_EMAIL"],
      personalized_footer: "Thank you for being a customer."
    };
  } catch (error) {
    throw error;
  }
};
```

Email Template usage:

```handlebars
<p>Support: {{custom_data.support_email}}</p>
<p>{{custom_data.personalized_footer}}</p>
```

Recommended environment variables:

```json
[
  {
    "name": "SUPPORT_EMAIL",
    "value": "support@example.com"
  }
]
```

---

## Integration Pattern: Payment Profile External Decisioning

Use this pattern when a `payment_profile` Function calls an external decisioning API and returns a flow response.

```javascript
const axios = require("axios");

exports.handler = async function(event, context) {
  try {
    const item = event.data.item_details;
    const decisionUrl = process.env["DECISION_API_URL"];
    const apiKey = process.env["DECISION_API_KEY"];

    if (!decisionUrl || !apiKey) {
      throw new Error("Missing decision API configuration.");
    }

    const decision = await axios.post(
      decisionUrl,
      {
        payment_amount: item.payment_amount,
        customer: item.customer,
        customer_card: item.customer_card,
        gateway_history: item.gateway_history
      },
      {
        headers: {
          Authorization: `Bearer ${apiKey}`,
          "Content-Type": "application/json"
        },
        timeout: 3000
      }
    );

    if (decision.data.abort === true) {
      return {
        next_output: "2",
        custom_error: decision.data.message || "Payment could not be processed."
      };
    }

    if (decision.data.gateway_id) {
      return {
        set_gateway_id: decision.data.gateway_id,
        next_node_id: decision.data.next_node_id
      };
    }

    return {
      next_output: "1"
    };
  } catch (error) {
    throw error;
  }
};
```

Important:

- Keep timeout low for payment-profile integrations.
- Always configure a red-output fallback path in the payment flow.
- Return only response properties needed by the flow.
- Do not call slow external systems from payment flows unless necessary.

---

## Integration Security Checklist

Before using a Function for third-party integration:

1. Store API keys and secrets in encrypted `environment_variables`.
2. Do not hardcode secrets in `function_code`.
3. Add only the dependencies required.
4. Load dependencies with CommonJS `require()`.
5. Add HTTP request timeouts.
6. Validate event payload fields before sending them externally.
7. Avoid sending unnecessary customer or payment data.
8. Avoid logging sensitive data.
9. Use idempotency keys when sending events that might be retried.
10. Handle third-party downtime gracefully.
11. For payment-profile Functions, keep execution within the 8-second response window.
12. For URL/webhook Functions, validate inbound payloads and restrict IPs where possible.
13. Return safe, minimal responses.
14. Test with realistic payloads before enabling production usage.

# Output Schema

A successful `EditFunction` response returns:

```json
{
  "api_call_id": "XXXXXXXXXXXXXXXXXXXX",
  "api_call_unix": 1740000000,
  "code": 1,
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "result": "..."
}
```

Fields:

| Field | Type | Description |
|---|---:|---|
| `api_call_id` | string | 20-character API call ID. |
| `api_call_unix` | integer | Unix timestamp when the API call was initiated. |
| `code` | integer | Response code. `1` indicates success. |
| `function_id` | string | 20-character ID of the edited Function. |
| `result` | string | Human-readable result message. |

---



---

# Function Deployment Status And Edit Availability

Before calling `EditFunction`, use `GetFunction` to confirm the Function deployment `status` is `READY`.

A Function must be `READY` before normal `EditFunction` updates. If status is `UPDATE_FAILED`, retry the dependency update after checking dependency errors.

Status behavior:

| Status | Meaning | EditFunction Availability | Trigger Availability |
|---|---|---|---|
| `READY` | The Function is ready. | Can be updated with `EditFunction`. | Can be triggered if configured/enabled for the trigger path. |
| `CREATING` | The Function is being created. | Cannot be updated. | Cannot be triggered. |
| `CREATE_FAILED` | Function creation failed. | Cannot be updated. | Cannot be triggered. |
| `UPDATING` | Dependencies are being redeployed after a dependency update. | Cannot be updated until deployment completes. | Can still be triggered. |
| `UPDATE_FAILED` | Dependency update failed. | Can retry the update after checking invalid dependencies or other deployment errors. | Can still be triggered. |

Deployment behavior:

- `CreateFunction` starts creation deployment.
- Updating `dependencies` with `EditFunction` triggers redeployment.
- Other `EditFunction` changes, such as trigger settings or `function_code`, do not trigger redeployment.
- After creation or dependency updates, it may take up to 5 minutes for the Function to become `READY`.
- Long polling is recommended when checking deployment status.
- If an `EditFunction` request returns a deployment/provisioning error, call `GetFunction`, inspect `status`, and wait for `READY` before retrying.

Best practices:

1. Use `GetFunction` to confirm `status: "READY"` before every `EditFunction` request.
2. Submit the `EditFunction` update.
3. If the update changed `dependencies`, use `GetFunction` and long poll until `status: "READY"` before submitting another update.
4. If `status` becomes `UPDATE_FAILED`, check for invalid dependency names or versions, then retry the update.
5. If the edit did not change `dependencies`, such as `function_code` or trigger settings, redeployment is not expected.


# Replacement vs Upsert Behavior

| Field | Behavior when provided |
|---|---|
| `name` | Updates the name. |
| `description` | Updates the description. |
| `enabled` | Updates enabled status. |
| `function_code` | Replaces the Function code. |
| `event_source` | Updates the event source. |
| `account_event_notations` | Updates/replaces event notations. |
| `account_event_filters` | Updates provided filters. |
| `timing_options` | Updates timing options. |
| `cron_expression` | Updates scheduled cron expression. |
| `cron_timezone` | Updates scheduled timezone. |
| `dependencies` | Replaces the existing dependency list. |
| `environment_variables` | Upserts variables; does not remove omitted existing variables. |
| `ip_restricted` | Updates IP restriction setting. |
| `ip_whitelist` | Updates/replaces whitelist values. |
| `custom_arguments` | Replaces the existing custom argument list. |

---

# Implementation Checklist

Before calling `EditFunction`:

1. Confirm the `function_id` is correct.
2. Call `GetFunction` and confirm `status: "READY"` before submitting the update.
3. Include only fields you intend to modify.
4. If editing `function_code`, submit complete handler-based code that includes `exports.handler = async function(event, context) { ... }`, or includes `callback` as the third argument when using callback style.
5. If editing `function_code`, ensure every execution path completes intentionally by returning a value, throwing an error, or calling `callback(error, response)`.
4. If changing `event_source`, remove or update fields that only apply to the old source.
5. For `account_event`, configure `account_event_notations` and use the first notation segment to find the event JSON body, for example `sale.created` → `https://revcent.com/documentation/files/function/event/account_event/sale.json`.
6. For `account_event`, add `account_event_filters` only when filtering is needed.
7. For `payment_profile`, use the Payment Profile event body JSON as the source of truth: `https://revcent.com/documentation/files/function/event/payment_profile.json`.
20. For delayed account events, provide valid `timing_options`.
8. For `schedule`, provide a valid 5-part `cron_expression`.
9. For `schedule`, provide a valid IANA `cron_timezone` when local time matters.
10. For dependencies, call `GetFunction` first if you need to preserve existing dependencies.
11. Load dependencies with CommonJS `require()`.
12. Do not use ESM `import` syntax.
13. Use valid installable dependency names and versions; `"latest"` is allowed.
14. If a dependency cannot be installed, provisioning will fail and the Function will error.
15. Dependency changes trigger redeployment; use `GetFunction` and long poll until `status: "READY"` before submitting another update.
13. Use environment variables for secrets instead of hardcoding them.
14. Remember environment variables are upserted, not fully replaced.
15. For `function_url`, use IP restriction where possible.
16. For normal `api_direct` triggering, define clear `custom_arguments` with letters and underscores only.
20. For `api_direct` filter Function usage, do not include `custom_arguments`; use the filter event body based on `item_type` and return only `pass` or `fail`.
17. Call `GetFunction` first if you need to preserve existing custom arguments.
18. Use the correct event-body JSON reference for the configured trigger type:
    - account_event → account_event/<item_type>.json
    - api_direct → https://revcent.com/documentation/files/function/event/api_direct.json; as AI Assistant / AI Voice Agent filter Function → https://revcent.com/documentation/files/function/event/filter/<item_type>.json
    - payment_profile → https://revcent.com/documentation/files/function/event/payment_profile.json
    - function_url → https://revcent.com/documentation/files/function/event/function_url.json
    - webhook → https://revcent.com/documentation/files/function/event/webhook.json
    - schedule → https://revcent.com/documentation/files/function/event/schedule.json
    - pre_agent → https://revcent.com/documentation/files/function/event/pre_agent.json (AI Voice Agent pre-agent Function for Handlebars instruction content)
19. If editing `dependencies`, call `GetFunction` after the update and long poll until `status: "READY"` before submitting another edit.
20. Test the Function with realistic payloads before enabling production behavior.
21. Enable the Function only after code and configuration are validated.

---

# Quick Reference

Rename only:

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "name": "Updated Function Name"
}
```

Disable Function:

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "enabled": false
}
```

Configure API-direct Function:

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "enabled": true,
  "event_source": "api_direct",
  "custom_arguments": [
    {
      "name": "sale_id",
      "description": "The 20-character sale ID."
    }
  ]
}
```

Configure account-event Function:

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "enabled": true,
  "event_source": "account_event",
  "account_event_notations": ["sale.created.success.paid"]
}
```

Configure scheduled Function:

```json
{
  "function_id": "XXXXXXXXXXXXXXXXXXXX",
  "enabled": true,
  "event_source": "schedule",
  "cron_expression": "0 9 * * *",
  "cron_timezone": "America/New_York"
}
```


---
Document Parent Directory
* [Operations](https://revcent.com/documentation/markdown/mcp/operation/index.md) - AI/MCP details and overviews for operations available within the RevCent MCP.

---
Document Parent Directory
* [Operations](https://revcent.com/documentation/markdown/mcp/operation/index.md) - AI/MCP details and overviews for operations available within the RevCent MCP.