# Define configuration and custom input Define fields that your users set in the Stripe Dashboard. You can ask users of your scripts for values that your script can use at runtime. This lets you change script behavior without rebuilding and redeploying. There are two approaches, depending on which extension point you use: - [Configuration](https://docs.stripe.com/extensions/scripts/define-config-and-schemas.md#define-configuration): Values set once when a user activates your extension, available at every runtime. - [Custom input](https://docs.stripe.com/extensions/scripts/define-config-and-schemas.md#define-custom-input): Values provided each time a user configures an action step in a workflow. ## Define configuration 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. These values are passed to your script’s methods in the `config` argument. 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. 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 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 { 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 { /** * @displayName Description * @minLength 1 * @maxLength 50 */ description: string; } ``` ## Supported types for configuration You can use standard TypeScript types such as `string`, `number`, and `boolean`. Import Stripe-specific types such as `MonetaryAmount`, `Percent`, `Time`, and `Decimal` 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` | The following image shows how the Dashboard renders the different supported data types. The example also shows how validations like maximum character length for the string field and maximum value for the number field appear. ![Configuration form with string, number, boolean, enum, monetary amount, and decimal field types in the Dashboard.](https://b.stripecdn.com/docs-statics-srv/assets/config-form.b900919bbb731c531f6679ef9edda8db.png) ## Define custom input Some extension points let you 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)