Documentation
Feedback
Guides

Bulk pricing import integration

The Bulk Pricing API allows for asynchronous processing of large-scale price updates by sending a single CSV file containing the price updates and letting the platform process them in the background. This guide is intended for developers and integrators who implement bulk pricing update flows on the VTEX platform.

To update the price of only one SKU, use the API

This API supports two types of pricing updates: base prices (cost price, base price, and list price per SKU) and fixed prices (price-table-specific prices with optional date ranges and minimum quantities). The workflow follows an async pattern where you start an import job, upload your CSV to a pre-signed URL, and then poll for status until processing completes.

The main actors involved are:

  • External pricing system (ERP or custom integration): Prepares the CSV file and orchestrates the import workflow.
  • Bulk Pricing API: Receives the import request, provides the upload URL, and processes the pricing data.
  • Cloud storage: Hosts the pre-signed URL where the CSV file is uploaded directly.

This guide covers the following integration flows:

How it works

Every bulk pricing import follows the same three-step async pattern, regardless of whether you are importing base or fixed prices:

  1. Your system sends a POST request to the Import prices endpoint, specifying the import type (base-prices or fixed-prices) and the file metadata (content type and size in bytes). The API returns a unique batchId and a pre-signed upload URL.
  2. Your system uploads the CSV file directly to the pre-signed URL using a PUT request with the headers provided in the response.
  3. Your system polls the Get batch status endpoint using the batchId to monitor processing progress. If errors occur, you retrieve the error details via the Get batch errors endpoint.

⚠️ The pre-signed upload URL has an expiration timestamp (expiresAt). You must complete the file upload before this time. If the URL expires, you need to start a new import job.

ℹ️ The pre-signed URL points directly to cloud storage. Do not replace it with the API base URL or any other endpoint.


_17
sequenceDiagram
_17
participant ExtSystem as External System
_17
participant PricingAPI as Bulk Pricing API
_17
participant Storage as Cloud Storage
_17
_17
ExtSystem->>PricingAPI: POST /api/price-importer/pvt/import/{importType}
_17
PricingAPI-->>ExtSystem: 200 OK (batchId, pre-signed upload URL)
_17
ExtSystem->>Storage: PUT CSV file to pre-signed URL
_17
Storage-->>ExtSystem: 200 OK
_17
loop Poll until terminal status
_17
ExtSystem->>PricingAPI: GET /api/price-importer/pvt/batches/{batchId}
_17
PricingAPI-->>ExtSystem: 200 OK (status, progress)
_17
end
_17
alt COMPLETED_WITH_ERRORS
_17
ExtSystem->>PricingAPI: GET /api/price-importer/pvt/batches/{batchId}/errors
_17
PricingAPI-->>ExtSystem: 200 OK (pre-signed URL to error CSV)
_17
end

Permissions

Each endpoint requires specific License Manager resources. Requests made without the proper permissions return a 403 Forbidden error.

EndpointProductCategoryResource
POST Import pricesPricingPrice ListModify prices
GET Get batch statusPricingPrice ListRead prices
GET Get batch errorsPricingPrice ListRead prices

⚠️ There are no predefined roles for these resources. You must create a custom role and assign the appropriate resources to it.

ℹ️ To prevent integrations from having excessive permissions, follow the best practices for managing API keys when assigning License Manager roles to integrations.

Bulk import flow

Use this unified flow to import either base or fixed prices. The high-level process is the same for both import types; differences are noted inline where relevant.

When to use this flow

  • Use this flow when you need to update pricing data for many SKUs at once.
  • Use base-price imports when you need to update cost, base, and optional list prices for SKUs.
  • Use fixed-price imports when you need to update sales-channel-specific prices, time-bound prices (Date From / Date To), or quantity-based rules (Min Quantity).

Main endpoints involved

  • POST /api/price-importer/pvt/import/{importType} – Start an import job. importType must be base-prices or fixed-prices. The response includes batchId and pre-signed upload details.
  • GET /api/price-importer/pvt/batches/{batchId} – Poll batch status and progress.
  • GET /api/price-importer/pvt/batches/{batchId}/errors – Retrieve a pre-signed URL to download a CSV with row-level errors.

Step-by-step

  1. Prepare a CSV file following the schema for the import type (see CSV schemas below). Ensure UTF-8 encoding, a comma delimiter, and a header row.
  2. Call POST /api/price-importer/pvt/import/{importType} with a JSON body containing contentType and contentLengthBytes. Optionally set output=email for email notifications.
    • Example importType values:
      • base-prices — base price import.
      • fixed-prices — fixed price import.
  3. Extract batchId and upload.url from the response.
  4. Upload the CSV to upload.url with PUT. Include Content-Type: text/csv and any headers in upload.headers.
  5. Poll GET /api/price-importer/pvt/batches/{batchId} until status is a terminal state (COMPLETED, COMPLETED_WITH_ERRORS, FAILED).
  6. If COMPLETED_WITH_ERRORS, call the errors endpoint to download a CSV with Error Code and Error Message columns, fix failing rows, and re-submit them as needed.

ℹ️ The upload URL expires at upload.expiresAt. If it expires before you upload, start a new import job.

Request examples

Start a base price import:


_10
curl -X POST \
_10
"https://{accountName}.vtexcommercestable.com.br/api/price-importer/pvt/import/base-prices?output=email" \
_10
-H "Content-Type: application/json" \
_10
-H "Accept: application/json" \
_10
-H "X-VTEX-API-AppKey: {appKey}" \
_10
-H "X-VTEX-API-AppToken: {appToken}" \
_10
-d '{
_10
"contentType": "text/csv",
_10
"contentLengthBytes": 524288000
_10
}'

Start a fixed price import:


_10
curl -X POST \
_10
"https://{accountName}.vtexcommercestable.com.br/api/price-importer/pvt/import/fixed-prices?output=email" \
_10
-H "Content-Type: application/json" \
_10
-H "Accept: application/json" \
_10
-H "X-VTEX-API-AppKey: {appKey}" \
_10
-H "X-VTEX-API-AppToken: {appToken}" \
_10
-d '{
_10
"contentType": "text/csv",
_10
"contentLengthBytes": 10485760
_10
}'

Generic response example (start import)


_12
{
_12
"batchId": "550e8400-e29b-41d4-a716-446655440000",
_12
"status": "AWAITING_UPLOAD",
_12
"upload": {
_12
"method": "PUT",
_12
"url": "https://pricing-bucket.s3.amazonaws.com/imports/550e8400.csv?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=600",
_12
"headers": {
_12
"Content-Type": "text/csv"
_12
},
_12
"expiresAt": "2026-01-12T20:10:00Z"
_12
}
_12
}

Upload the CSV file:


_10
curl -X PUT \
_10
"https://pricing-bucket.s3.amazonaws.com/imports/550e8400.csv?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=600" \
_10
-H "Content-Type: text/csv" \
_10
--data-binary @your-import-file.csv

CSV schemas and examples

Base prices CSV schema

FieldTypeRequiredDescriptionExample
SKU IDStringYesSKU identifier.SKU-12345
Cost PriceDecimalYesCost price of the item.10.00
Base PriceDecimalYesBase price of the item.25.00
List PriceDecimalNoList price of the item.30.00

CSV example (base prices):


_10
SKU ID,Cost Price,Base Price,List Price,Child Account
_10
1,45.50,59.99,65,
_10
2,47.50,62.30,70.50,ChildAccountValue

Fixed prices CSV schema

FieldTypeRequiredDescriptionExample
SKU IDStringYesSKU identifier.SKU-12345
Trade PolicyStringYesThe price table to modify.gold
PriceDecimalYesThe fixed price of the item in the price table.25.00
List PriceDecimalNoList price of the item in the price table.30.00
Min QuantityIntegerNoMinimum quantity required to start applying this price.2
Date FromStringNoDate from which the price applies, in ISO 8601 UTC.2025-07-29T18:20:37Z
Date ToStringNoEnd date for the fixed price, in ISO 8601 UTC.2025-08-29T18:20:37Z

CSV example (fixed prices):


_10
SKU ID,Trade Policy,Price,List Price,Min Quantity,Date From,Date To,Child Account
_10
25,gold,10.80,20.00,2,2025-07-29T18:20:37Z,2025-08-29T18:20:37Z,ChildAccountValue
_10
25,silver,11.80,,2,2025-07-29T18:20:37Z,2025-08-29T18:20:37Z,
_10
26,gold,15.00,17.00,,,,

Error handling

HTTP StatusMeaningAction
200Batch accepted for processing.Extract batchId and upload.url, then upload the CSV.
401Unauthorized.Verify your API key credentials or user token.
403Forbidden.Ensure your credentials have the Modify prices permission for imports and Read prices for status/errors.
413File exceeds the 500 MB size limit.Split your CSV into smaller files and submit separate import jobs.
422Validation error in the file or request body.Review row-level errors returned in the error CSV.
429Rate limit exceeded.Wait and retry the request after a delay.
503Service unavailable.Retry with exponential backoff.

⛔ If you receive a 413 error, do not retry with the same file. Split the CSV into multiple files, each under 500 MB, and submit them as separate import jobs.

⚠️ For fixed-price imports: Ensure that Date From is earlier than Date To. Rows with invalid date ranges will fail during processing and appear in the error report.

Batch monitoring and error handling flow

After uploading a CSV file, use this flow to track the import progress and retrieve error details when processing finishes with errors.

When to use this flow

  • Use this flow after uploading a CSV file to monitor the batch processing status.
  • Use this flow to determine when the import has completed and whether it succeeded or had errors.
  • Use this flow to download a detailed error report when the batch finishes with the COMPLETED_WITH_ERRORS status.

Main endpoints involved

Status lifecycle

A batch job progresses through the following statuses:

StatusDescription
AWAITING_UPLOADBatch created, waiting for the CSV file upload.
RECEIVEDFile received, waiting for processing to start.
VALIDATINGAn initial file validation is being performed.
PROCESSINGThe batch is actively processing rows.
DOCUMENTINGThe import results are being generated.
COMPLETEDAll rows processed successfully.
COMPLETED_WITH_ERRORSProcessing finished, but some rows had errors.
FAILEDProcessing failed entirely.

ℹ️ Terminal statuses are COMPLETED, COMPLETED_WITH_ERRORS, and FAILED. Stop polling once the batch reaches one of these statuses.

Step-by-step

  1. After uploading the CSV file, start polling the batch status endpoint using the batchId from the import response.
  2. Check the status field in each response. Continue polling until the status reaches a terminal state.
  3. Use the bytesProcessed and bytesTotal fields to calculate progress during the PROCESSING stage.
  4. If the final status is COMPLETED, all rows were imported successfully.
  5. If the final status is COMPLETED_WITH_ERRORS, call the Get batch errors endpoint to download the error report. The errorCount field tells you how many rows failed.
  6. If the final status is FAILED, the entire batch failed. Review the batch metadata and your CSV file for issues.

⚠️ Implement a polling interval with exponential backoff to avoid excessive API calls. A reasonable starting interval is 5 seconds, increasing gradually for long-running imports.

Request example – Get batch status


_10
curl -X GET \
_10
"https://{accountName}.vtexcommercestable.com.br/api/price-importer/pvt/batches/550e8400-e29b-41d4-a716-446655440000" \
_10
-H "Accept: application/json" \
_10
-H "X-VTEX-API-AppKey: {appKey}" \
_10
-H "X-VTEX-API-AppToken: {appToken}"

Response example – Get batch status


_13
{
_13
"batchId": "550e8400-e29b-41d4-a716-446655440000",
_13
"type": "base",
_13
"status": "COMPLETED_WITH_ERRORS",
_13
"outputs": [
_13
"email:user@example.com"
_13
],
_13
"bytesProcessed": 13800000,
_13
"bytesTotal": 13800000,
_13
"errorCount": 12,
_13
"createdAt": "2026-01-12T20:00:00Z",
_13
"startedAt": "2026-01-12T20:01:00Z"
_13
}

  • type: Indicates the import type (base for base prices, fixed for fixed prices).
  • status: Current processing status. Here, COMPLETED_WITH_ERRORS means some rows failed.
  • bytesProcessed / bytesTotal: Track upload and processing progress.
  • errorCount: Number of rows that failed. Use this to decide whether to retrieve the error report.
  • outputs: Configured notification channels for when the job finishes.

Request example – Get batch errors


_10
curl -X GET \
_10
"https://{accountName}.vtexcommercestable.com.br/api/price-importer/pvt/batches/550e8400-e29b-41d4-a716-446655440000/errors" \
_10
-H "Accept: application/json" \
_10
-H "X-VTEX-API-AppKey: {appKey}" \
_10
-H "X-VTEX-API-AppToken: {appToken}"

Response example – Get batch errors


_10
{
_10
"url": "https://pricing-bucket.s3.amazonaws.com/errors/550e8400-e29b-41d4-a716-446655440000.csv?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=600"
_10
}

The url field contains a pre-signed URL to download a CSV file with error details. This CSV has the same format as your original import file, with two additional columns: Error Code and Error Message. Download the file, review the errors, fix the affected rows, and re-submit them in a new import job.

CSV format requirements

All CSV files must follow these formatting rules:

RequirementValue
EncodingUTF-8
Header rowRequired (first row)
DelimiterComma (,)
Quote characterDouble quote (")

Output notifications

Use the output query parameter in the Import prices request to configure email notifications when the job finishes:

ValueDescription
emailSends an email notification when processing completes. The target email address is configured separately in the platform settings.
Contributors
2
Photo of the contributor
Photo of the contributor
Was this helpful?
Yes
No
Suggest Edits (GitHub)
Contributors
2
Photo of the contributor
Photo of the contributor
Was this helpful?
Suggest edits (GitHub)
On this page