Stripe | Financial Infrastructure to Grow Your Revenue

Stripe | Financial Infrastructure to Grow Your Revenue

4466 articles

Running a batch job


Public preview

Running a batch job Public preview

Create, upload, monitor, and download results for a batch job.

For the complete API reference, including all available parameters and response fields, see the Batch Jobs API reference.

To process a batch job, follow these steps:

  1. Create a batch job and specify the target API endpoint.
  2. Upload the input file with your batch requests.
  3. Monitor job status through webhooks or polling.
  4. Download the results .

Create a batch job

To start, create a batch job by sending a POST request to /the relevant part of the product. Specify the target endpoint and any processing options:

Command Line

cURL

The content type for this request is a JSON file. This returns a batch job object with a ready_for_upload status. The upload URL and its expiration time are in the status_details field:

The status_details object changes based on the current status. When the job is ready_for_upload, it contains the presigned upload URL and its expiration timestamp.

Parameters

ParameterRequiredDescription
endpoint.pathYesThe API endpoint to target (for example, /v1/subscriptions/:id/migrate). See Supported endpoints.
endpoint.http_methodYesThe HTTP method for the endpoint. Currently only post is supported.
skip_validationNoSet to true to skip input file validation and start processing immediately. Defaults to false.
notification_suppressionNoControls whether webhooks from the underlying API operations are delivered. Set {"scope": "all"} to suppress operation-level webhooks. Batch-level events are always delivered regardless of this setting. Defaults to {"scope": "none"}.
metadataNoKey-value pairs for your internal tracking. Metadata is included in batch job events, including failure events.

Upload the input file

After creating the batch job, upload your input file to the URL in status_details.ready_for_upload.upload_url.url. Use a PUT request with the file contents:

Command Line

curl {UPLOAD_URL} \
 -X PUT \
 -T input.jsonl \
 -H "Content-Type: application/jsonlines"

The input file for this request must be a the related setting file, and the content type must be application/jsonlines. After the upload completes, Stripe automatically starts processing. There’s no separate start step.

Warning

A 200 response to the PUT comes from storage (Amazon S3), which accepts the raw bytes directly through the presigned URL. It confirms only that the upload succeeded and that the Content-Type header was correct. It doesn’t mean Stripe has inspected the file or that the contents passed validation.

File-body validation (valid the related setting, required fields, and so on) runs asynchronously after the upload. When skip_validation is false, the job moves to validating and then to validation_failed if the contents are invalid.

To learn the outcome, poll the batch job ( GET /the relevant part of the product/{the related setting}) and inspect its status and status_details.

The upload URL expires 5 minutes after batch job creation. Check the expires_at field for the exact deadline. If the URL expires before you upload the file, the job status changes to upload_timeout, and you must create a new batch job. Generate the input file before you create the batch job so you can upload it promptly.

Input file format

The file must be UTF-8 encoded and use the related setting format (newline-delimited JSON, one object per line). Each line represents a single API request to the target endpoint. CSV and other formats aren’t supported.

The file is capped at 2 million lines. Stripe counts the lines after the upload completes, and jobs that exceed the cap transition to validation_failed status without processing any requests. To process more than 2 million lines, split the workload into multiple batch jobs of at most 2 million lines each and submit them sequentially—wait for one job to finish before you create the next. Running several large batch jobs concurrently can be slower and less reliable than running the same work as sequential jobs. If you need more capacity than this, contact Stripe support.

Each JSON object supports these fields:

FieldRequiredDescription
idYesA unique identifier to correlate this request with its result. The IDs on the path parameters and the IDs on the endpoint must match, though the user is free to choose how to name them: must match /^[A-Za-z0-9_-]+$/.
path_paramsConditionalPath parameters for the endpoint. Required when the endpoint path includes placeholders (for example, :id). The keys in path_params must match the placeholders in the endpoint path exactly.
paramsNoRequest body parameters for the API call. Variations can occur based on the API method.
contextNoA Stripe account ID. Use this to execute the request against a specific account, such as a connected account.

Example input file

API Method:

For the POST /v1/customers endpoint:

{
 "id": "req_001",
 "params": {"email": "alice@example.com", "name": "Alice Smith"}
}
{
 "id": "req_002",
 "params": {"email": "bob@example.com", "name": "Bob Jones", "phone": "+18005550123"}
}
{
 "id": "req_003",
 "context": "acct_1234567890",
 "params": {"email": "carol@example.com", "name": "Carol White", "metadata": {"import_id": "legacy_001"}}
}

Each id must be unique within the file. Stripe uses it to correlate requests with results, because the results file isn’t ordered the same way as the input file.

Monitor job status

You can track your batch job by polling the retrieve endpoint or by listening for webhook events. We recommend using webhook events for production integrations.

Poll for status

Command Line

cURL

The content type for this request is a json file. While the job is running, status_details includes real-time progress counts:

{
 "status": "in_progress",
 "status_details": {
 "in_progress": {
 "success_count": "1",
 "failure_count": "0"
 }
 }
}

During the validating phase, status_details includes a validated_count field that shows how many rows Stripe has validated so far.

Batch job API calls appear in the Stripe Dashboard or Workbench request logs. The underlying API calls don’t appear in the request logs. Use the retrieve endpoint or webhook events to monitor progress. To debug individual request failures, check the results file.

Job lifecycle

After you upload the input file, the batch job progresses through these statuses:

StatusDescription
ready_for_uploadThe batch job was created and is waiting for the input file.
validatingStripe accepted the uploaded file and is validating it. Skipped when skip_validation is true.
in_progressValidation passed (or was skipped) and Stripe is processing requests.
completeAll requests have been processed. Results are available for download.
cancellingA cancelation was requested. Stripe is finishing in-flight requests.

Terminal statuses

StatusDescription
validation_failedThe input file contains errors. No requests were processed. Check the batch job object for error details. This is only applicable when skip_validation: false.
batch_failedAn unexpected error occurred during processing.
cancelledThe batch job was canceled. Partial results might be available.
upload_timeoutThe upload URL expired before the file was uploaded. Create a new batch job.
timeoutThe batch job exceeded the maximum processing duration of 7 days. Partial results might be available.

Validation

When skip_validation is false (the default) Stripe validates the entire input file before processing any requests. This validation catches errors such as:

  • Invalid JSON in any row.
  • Missing or invalid id fields.
  • Duplicate IDs.
  • Missing required path _ params for the target endpoint.
  • Malformed parameters.

If validation fails, the status changes to validation_failed, and Stripe doesn’t attempt any requests. The batch job object includes details about the first error it encounters.

When skip_validation is true, the job transitions directly from ready_for_upload to in_progress after upload. Errors in individual requests appear in the results file instead of blocking the entire batch.

Webhook events

Batch jobs emit v2 thin events for every lifecycle transition. To receive these events, you must configure a v2 event destination.

Batch job events require v2 event destinations. They aren’t delivered to v1 webhook endpoints.

The following events are available:

Event typeDescription
v2.core.batch_job.createdA batch job was created.
v2.core.batch_job.ready_for_uploadThe batch job is ready for file upload.
v2.core.batch_job.validatingFile upload complete, validation in progress.
v2.core.batch_job.validation_failedInput file validation failed.
v2.core.batch_job.completedAll requests have been processed.
v2.core.batch_job.batch_failedThe batch job failed unexpectedly.
v2.core.batch_job.canceledThe batch job was canceled.
v2.core.batch_job.timeoutThe batch job exceeded maximum processing duration.
v2.core.batch_job.upload_timeoutThe upload URL expired before the file was uploaded.
v2.core.batch_job.updatedThe batch job status or progress changed.

All batch job events include the metadata you provided when creating the job. Use this to correlate events with your internal systems.

When notification_suppression is set to {"scope": "all"}, webhooks from the underlying API operations (for example, subscription update events) are suppressed. Batch-level events listed above are always delivered regardless of this setting.

Download the results

When the batch job reaches complete status, the status_details field includes a summary of successes and failures, along with a presigned download URL for the output file:

Download the file using the URL in status_details.complete.output_file.download_url.url. Stripe provides an output file when the batch job reaches any of these states:

  • complete
  • cancelled
  • timeout
  • validation _ failed

To see when the download URL expires, check the expires_at field for the deadline.

The results file contains both successful and failed requests in a single file. To find failures, filter for rows where status isn’t 200.

Results file format

The output file uses the related setting format (one JSON object per line). Each line contains these fields:

FieldDescription
idThe request ID from the input file. Use this to correlate results with requests.
responseThe full API response object. Contains the resource on success, or an error object on failure.
statusThe HTTP status code as an integer (for example, 200, 402).
contextThe connected account the request ran against.

Example results file

Successful requests return the full API resource in the response field:

{
 "id": "req_001",
 "response": {
 "id": "sub_1AbCdEfGhIjKlMn",
 "object": "subscription",
 "status": "active",
 "billing_cycle_anchor": 1710021331,
 "current_period_end": 1712613331,
 "current_period_start": 1710021331
 },
 "status": 200
}
{
 "id": "req_002",
 "response": {
 "id": "sub_2BcDeFgHiJkLmNo",
 "object": "subscription",
 "status": "active",
 "billing_cycle_anchor": 1710021331,
 "current_period_end": 1712613331,
 "current_period_start": 1710021331
 },
 "status": 200
}

Failed requests return an error object:

{
 "id": "req_003",
 "response": {
 "error": {
 "message": "This subscription cannot be migrated because it is not active. Current status is canceled.",
 "type": "invalid_request_error",
 "code": "resource_invalid_state"
 }
 },
 "status": 400
}

When an input line includes a context, the corresponding output includes it:

{
 "id": "req_001",
 "context": "acct_1234567890",
 "response": {
 "id": "sub_1AbCdEfGhIjKlMn",
 "object": "subscription",
 "status": "active"
 },
 "status": 200
}

Results aren’t returned in the same order as the input file. Use the id field to match each result to its corresponding request.

Cancel a batch job

You can cancel a batch job that hasn’t completed yet by sending a POST request:

Command Line

cURL

Cancelation is asynchronous. The job first transitions to cancelling while in-flight requests finish, then to cancelled. Any partial results from requests processed before cancelation are available in the results file.

Use with Connect

Platform accounts can run batch jobs on behalf of connected accounts. Create the batch job using your platform’s API key as normal. To target a connected account for individual requests in the input file, set the context field to the connected account ID. This is the per-request equivalent of the Stripe-Account header in direct API calls.

Command Line

cURL

In the input file, add context to each line that should run as a connected account:

{"id": "req_001", "context": "acct_1AbCdEfGhIjKlMn", "path_params": {"id": "sub_1AbCdEfGhIjKlMn"}, "params": {"billing_cycle_anchor": "unchanged"}}
{"id": "req_002", "context": "acct_2BcDeFgHiJkLmNo", "path_params": {"id": "sub_2BcDeFgHiJkLmNo"}, "params": {"billing_cycle_anchor": "unchanged"}}
{"id": "req_003", "path_params": {"id": "sub_3CdEfGhIjKlMnOp"}, "params": {"billing_cycle_anchor": "unchanged"}}

Lines without context run as the platform account. Lines with context run as the specified connected account. You can mix both in the same batch file.

Last verified 2026-09-24

Is this helpful?