Stripe Payments ExecModule
Overview
StripeModule connects a ValkyrAI workflow to Stripe API v1 without placing API keys in workflow configuration. It supports bounded charge reads and explicit customer, charge, subscription, and refund writes. All write operations require a caller-supplied idempotency key, and financial writes also require an explicit confirmation flag.
The module is registered as:
com.valkyrlabs.workflow.modules.payment.StripeModule
This guide covers StripeModule. The separate legacy Stripe Checkout Session guide covers StripeCheckoutModule.
Usage
- Bind a READY Stripe
IntegrationAccountto the module's normalized auth configuration. - Select one supported
operation. - Provide the operation-specific inputs.
- For every write, provide a stable
idempotency_keythat is not reused with different parameters. - For
create_charge,create_subscription, orrefund, setconfirm_financial_actiontotrueonly after the workflow has approved that exact action. - Execute the workflow and inspect
status,dataoritems,attempts, andrequest_id.
Inputs
| Input | Required | Description |
|---|---|---|
operation | Yes | create_charge, create_customer, create_subscription, refund, list_charges, or get_charge. |
amount | By operation | Smallest-currency-unit amount for create_charge; optional partial amount for refund. Range: 1–99,999,999. |
currency | For charge | Three-letter currency code. Default: usd. |
customer_id | For charge/subscription | Stripe customer ID beginning with cus_. |
price_id | For subscription | Stripe Price ID beginning with price_. |
charge_id | For get/refund | Stripe Charge ID beginning with ch_. |
email | For customer | Bounded customer email address. |
name | No | Customer display name, at most 256 characters. |
description | No | Charge or customer description, at most 500 characters. |
quantity | No | Subscription item quantity from 1 through 999. Default: 1. |
reason | No | Refund reason: duplicate, fraudulent, or requested_by_customer. |
limit | No | Charge page size from 1 through 100. Default: 25. |
starting_after | No | Charge cursor from a previous next_cursor. |
idempotency_key | Every write | Stable caller correlation key, 1–255 characters. |
confirm_financial_action | Financial writes | Must be true for charge, subscription, and refund writes. |
Raw auth, api_key, apiKey, secretKey, secret_key, mock, and test fields are rejected before provider execution.
Outputs
| Output | Description |
|---|---|
status | success or error. |
operation | Normalized operation name. |
data | Allowlisted fields from one Stripe resource. |
resource_id | Validated Stripe resource ID for a single-resource success. |
items | Allowlisted charge summaries for list_charges. |
count | Number of charge summaries in this page. |
has_more | Whether Stripe reports another page. |
next_cursor | Last returned charge ID when another page exists. |
request_id | Stripe Request-Id, when supplied, for support correlation. |
attempts | HTTP attempt count. Write operations always report one attempt. |
error | Safe object containing code, message, retryable, and optional httpStatus. |
The module does not return raw provider bodies. Returned resource maps include only bounded identity, status, amount, currency, customer, time, and state fields relevant to workflow decisions.
IntegrationAccount Requirements
The bound IntegrationAccount must:
- have status
READY; - store a Stripe restricted key (
rk_test_…orrk_live_…) or secret key (sk_test_…orsk_live_…) in theapiKeySecureField; - use least-privilege Stripe permissions for the configured operations;
- expose no credential through module inputs, configuration JSON, logs, output, or error text.
Restricted keys are preferred when their resource permissions cover the workflow. Test-mode and live-mode access are determined by the bound key; a workflow flag cannot switch modes.
Configuration
stripeAccount is the only authentication configuration. The remaining normalized fields mirror the inputs above, plus safe_read_retries:
| Configuration | Default | Constraint |
|---|---|---|
safe_read_retries | 1 | 0–2 retries, GET operations only. |
limit | 25 | 1–100 charges per page. |
quantity | 1 | 1–999 subscription items. |
currency | usd | Exactly three letters. |
The provider destination is fixed to https://api.stripe.com/v1. Redirects are disabled, response bodies are capped at 2 MiB, and network calls use bounded connect, read, write, and total timeouts.
Operations
list_charges
Reads one bounded page from /v1/charges. Supply starting_after from the previous next_cursor to continue. Safe reads may retry HTTP 408, 429, 500, 502, 503, or 504 within the configured bound.
get_charge
Reads one charge by charge_id and validates that the response contains a ch_ resource ID.
create_customer
Creates one Stripe customer from a bounded email, optional name, and optional description. A stable idempotency_key is required. The module sends exactly one POST attempt.
create_charge
Creates one charge for an existing customer_id. amount, currency, idempotency_key, and confirm_financial_action=true are required. The module sends exactly one POST attempt.
create_subscription
Creates one subscription for a customer_id and price_id, with bounded quantity. It sets Stripe payment_behavior=default_incomplete, requires an idempotency key plus explicit financial confirmation, and sends one POST attempt.
refund
Creates one full or partial refund for charge_id. Optional reason is allowlisted. The operation requires an idempotency key plus explicit financial confirmation and sends one POST attempt.
Errors and Failure Modes
| Code | Meaning | Recovery |
|---|---|---|
VALIDATION_ERROR | Missing or malformed input, forbidden raw auth/mock field, missing idempotency key, or missing financial confirmation. | Correct the named input. No provider request was sent. |
UNSUPPORTED_OPERATION | The requested operation is outside the allowlist. | Select one documented operation. |
INTEGRATION_ACCOUNT_REQUIRED | No Stripe account is bound. | Bind a Stripe IntegrationAccount. |
INTEGRATION_ACCOUNT_NOT_READY | The account is not exactly READY. | Repair or reauthorize the account before retrying. |
STRIPE_HTTP_<status> | Stripe returned a non-success response. | Use request_id for diagnosis. Reconcile writes by idempotency key before retrying. |
NETWORK_ERROR | The request failed before a verified response. | Reads may retry automatically. Treat writes as ambiguous and reconcile Stripe state first. |
RESPONSE_TOO_LARGE | Stripe exceeded the 2 MiB response cap. | Narrow the request or page size. |
INVALID_PROVIDER_RESPONSE | A successful response lacked the expected resource shape or ID. | Inspect Stripe using request_id; do not assume the write failed. |
Credential values and raw Stripe error bodies are never included in the output. A transient write response is marked non-retryable because provider commit state may be ambiguous.
Example
Create one approved subscription:
{
"operation": "create_subscription",
"customer_id": "cus_P3d9Example",
"price_id": "price_1PExample",
"quantity": 1,
"idempotency_key": "order-42-subscription-v1",
"confirm_financial_action": true
}
Expected normalized result:
{
"status": "success",
"operation": "create_subscription",
"resource_id": "sub_1PExample",
"data": {
"id": "sub_1PExample",
"object": "subscription",
"status": "incomplete",
"customer": "cus_P3d9Example",
"livemode": false
},
"attempts": 1,
"request_id": "req_Example"
}
Notes
- Pagination is explicit:
list_chargesreturns at most 100 items and anext_cursorwhenhas_moreis true. - Only GET operations retry, and only for bounded transient statuses or transport failures.
- Writes use one HTTP attempt even if
safe_read_retriesis set. - Stripe idempotency keys reduce duplicate writes, but callers must keep the same parameters for a key and reconcile ambiguous responses before retrying.
- Refunds can be financially destructive and cannot be dry-run. The confirmation flag authorizes only the exact otherwise-valid request; it does not bypass validation or IntegrationAccount checks.
- Provider execution is not validated by the repository test suite because no live Stripe credential is used. Request construction, validation, retry boundaries, response mapping, catalog discovery, and secret redaction are tested deterministically.