# Custom Action

Learn about the Custom Action and its methods.

Custom actions let apps define actions you can add to Stripe Workflows. When a workflow triggers a custom action, Stripe calls the extensions execute method to run it. Apps can also implement get_form_state to power dynamic form behavior at configuration time, enabling dynamic dropdowns and dynamic form fields (for example, template merge variables that appear after selecting a template).

## ID

`extend.workflows.custom_action`

## Methods

### The Execute method 

Executes the custom action at workflow runtime. Called when a workflow triggers this action, with the configured input values.

|  |
| **Implementation types** | Script, Remote function |
| **Optionality** | You must implement this method. |
| **Retry policy** | Stripe doesn’t retry failed requests. |

#### Parameters 

Properties of the `request` object Stripe passes to this method. Your method also receives `config` (your defined input type) and `context` (Stripe execution metadata).

| Name | Type | Nullable | **Description** |
| --- | --- | --- | --- |
| `customInput` | `Record<string, unknown>` | No | Custom input data for the action, validated against the app’s input_schema. Contains the field values configured by the user in the workflow builder. |

#### Return value 

This method doesn’t return a value.

#### Examples 

```typescript
export default class MyCustomAction implements Extend.Workflows.CustomAction<MyCustomActionConfig> {
  execute(
    request: Extend.Workflows.CustomAction.ExecuteCustomActionRequest,
    config: MyCustomActionConfig,
    context: Context,
  ): Extend.Workflows.CustomAction.ExecuteCustomActionResponse {
    // Your implementation here
    return null;
  }
}
```

### The GetFormState method 

Returns the current form state for the action’s configuration UI. Called at configuration time (not runtime) to power dynamic form behavior, including dropdown options, dynamic JSON schemas, field visibility, and validation.

|  |
| **Implementation types** | Script, Remote function |
| **Optionality** | You must implement this method. |
| **Retry policy** | Stripe doesn’t retry failed requests. |

#### Parameters 

Properties of the `request` object Stripe passes to this method. Your method also receives `config` (your defined input type) and `context` (Stripe execution metadata).

| Name | Type | Nullable | **Description** |
| --- | --- | --- | --- |
| `changedField` | `string` | Yes | The name of the field that just changed, triggering this request. Empty on initial form load; set to the field name (for example, `audience_id`) when a user changes a value. |
| `values` | `Record<string, unknown>` | No | Current form field values. Contains all field values in the form, including fields the user has not yet interacted with (which might be null). |

#### Return value 

| Name | Type | Nullable | **Description** |
| --- | --- | --- | --- |
| `config` | [`Extend.Workflows.CustomAction.FormStateFieldConfig`](https://docs.stripe.com/extensions/custom-action.md#get_form_state-extend-workflows-custom-action-form-state-field-config) | No | Per-field configuration keyed by field name. |
| `values` | `Record<string, unknown>` | No | Updated form field values. Use this to set defaults, clear dependent fields when a parent changes, or preserve matching values across schema changes. Only fields included here are updated. Omitted fields keep their current values. |

#### Examples 

```typescript
export default class MyCustomAction implements Extend.Workflows.CustomAction<MyCustomActionConfig> {
  getFormState(
    request: Extend.Workflows.CustomAction.GetFormStateRequest,
    config: MyCustomActionConfig,
    context: Context,
  ): Extend.Workflows.CustomAction.GetFormStateResponse {
    // Your implementation here
    return {
      config: {
        options: {
          label: '',
          value: '',
        },
        schema: null,
      },
      values: null,
    };
  }
}
```

### Types

##### Extend.Workflows.CustomAction.FormStateFieldConfig 

Configuration for a single form field, returned by GetFormState.

| Name | Type | Nullable | **Description** |
| --- | --- | --- | --- |
| `disabled` | `boolean` | Yes | Whether the field is disabled (non-interactive). |
| `error` | `string` | Yes | Error message displayed on the field. Blocks saving the workflow. |
| `hidden` | `boolean` | Yes | Whether the field is hidden from the form. |
| `options` | [`Extend.Workflows.CustomAction.SelectOption`](https://docs.stripe.com/extensions/custom-action.md#get_form_state-extend-workflows-custom-action-select-option) | No | Dropdown options for `dynamic_select` fields. |
| `schema` | `Record<string, unknown>` | No | JSON Schema for dynamic_schema fields. Defines the structure of a dynamic object field (for example, template merge variables). V0 limitation: must be a flat object with string properties only. |
| `warning` | `string` | Yes | Warning message displayed on the field. You can still save the workflow. |

##### Extend.Workflows.CustomAction.SelectOption 

An option in a dynamic_select dropdown.

| Name | Type | Nullable | **Description** |
| --- | --- | --- | --- |
| `label` | `string` | No |  |
| `value` | `string` | No |  |
