# Define configuration and custom input

Define configuration fields that your users set in the Stripe Dashboard.

When a user [activates](https://docs.stripe.com/extensions/how-extensions-work.md#lifecycle) an extension, you can ask them for values that your script can use at runtime. For example, a billing extension for prorations might ask users to set a maximum proration amount. A custom action that sends email might ask which of the preconfigured email templates to use.

## How configuration works

1. You add properties to your config interface in your extension’s `src/index.ts`.
1. When you build or upload your app, Stripe converts the interface into a JSON schema stored in `generated/config.schema.json`.
1. When a user sets up your extension, a form with these fields appears in the Dashboard UI. The user provides static values or instance-specific objects as input to this form.
1. At runtime, Stripe passes the user-provided values to your script’s methods in the `config` argument so that you can use them in your custom logic.

Each property has a data type. Stripe renders a specific UI control for each type and applies default validations. You can add additional validation rules using TSDoc annotations.

## Add fields to your config interface

This example adds `description` as a `string` data type to the config interface.

```ts
interface MyExtensionConfig extends Record<string, unknown> {
  description: string;
}
```

You can then add TSDoc annotations to set validation rules. Stripe enforces these rules when the user submits the form.

```ts
interface MyExtensionConfig extends Record<string, unknown> {
  /**
   * @displayName Description
   * @minLength 1
   * @maxLength 50
   */
  description: string;
}
```

## Supported types

You can use standard TypeScript types like `string`, `number`, and `boolean`. For Stripe-specific types like `MonetaryAmount`, `Percent`, `Decimal`, and `Timestamp`, import them from `@stripe/extensibility-sdk/stdlib`.

Each type has its own set of available TSDoc validators:

| Type    | Validators                                                                                    |
| ------- | --------------------------------------------------------------------------------------------- |
| String  | - `@minLength`
  - `@maxLength`
  - `@pattern`                                                |
| Boolean | Validated to `true` or `false` by default                                                     |
| Enum    | Validated to the declared string union values by default                                      |
| Decimal | - `@minimum`
  - `@maximum`
  - `@exclusiveMinimum`
  - `@exclusiveMaximum`
  - `@multipleOf` |

## Define custom input

An extension point may allow you to define a custom input schema. Unlike configuration, which is set once at activation, custom input is provided each time a user configures an action step in the workflow builder. This lets you request input that’s specific to each workflow, for example, which email template to use. These values are passed to your `execute` method at runtime as `request.customInput`.

> #### Custom actions only
> 
> Only the Workflows [custom action extension point](https://docs.stripe.com/extensions/custom-actions/how-custom-actions-work.md) supports custom input. Billing extension points don’t use custom input.

You define custom input by adding two JSON files to your extension’s `src/` directory:

- `custom_input.schema.json`: A JSON Schema that defines the fields and their types
- `custom_input.ui.schema.json`: A UI schema that controls how the fields render in the workflow builder (layout, dynamic selects, conditional visibility)

### Define the input schema

Create `custom_input.schema.json` in your extension’s `src/` directory. This defines the fields and their types using [JSON Schema](http://json-schema.org/):

```json
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "title": "Name",
      "description": "The name of the item."
    },
    "description": {
      "type": "string",
      "title": "Description",
      "description": "A brief description of the item."
    }
  },
  "required": ["name", "description"],
  "additionalProperties": false
}
```

### Define the UI schema

Create `custom_input.ui.schema.json` in the same directory. This controls the layout and rendering of your fields in the workflow builder. You must add a `Control` element for each field you want to display. Fields without a corresponding control don’t appear in the UI:

```json
{
  "type": "VerticalLayout",
  "elements": [
    {
      "type": "Control",
      "scope": "#/properties/name"
    },
    {
      "type": "Control",
      "scope": "#/properties/description"
    }
  ]
}
```

Use `"format": "dynamic_select"` in the element’s `options` to render a field as a dropdown populated by `get_form_state`.

### Reference in the manifest

Add both files under `methods.execute.custom_input` in `stripe-app.yaml`:

```yaml
methods:
  execute:
    implementation_type: "script"
    custom_input:
      input_schema:
        type: "json_schema"
        content: "extensions/my-extension/src/custom_input.schema.json"
      ui_schema:
        type: "jsonforms"
        content: "extensions/my-extension/src/custom_input.ui.schema.json"
  get_form_state:
    implementation_type: "script"
```

### Access custom input at runtime

Stripe passes custom input values to your `execute` method in `request.customInput`:

```ts
execute(
  request: Extend.Workflows.CustomAction.ExecuteCustomActionRequest,
  _config: MyCustomActionConfig,
  _context: Context
) {
  const input = request.customInput ?? {};
  const name = input.name;
  const description = input.description;

  // Use these values in your action logic
  return {};
}
```

Make custom input fields dynamic by using the `get_form_state` method, which populates dropdown options and controls field visibility based on user selections.

## See also

- [Create the schemas](https://docs.stripe.com/extensions/custom-actions/build-with-script.md#create-schemas)
- [Build a custom action with a script](https://docs.stripe.com/extensions/custom-actions/build-with-script.md)
- [Build a custom action with a remote function](https://docs.stripe.com/extensions/custom-actions/build-with-remote-function.md)
