Skip to content

Export and import data

Open .md

Large exports, such as every sales order in a quarter, run in the background. You start one, wait for it to be ready, then download the file.

  1. Start itThe answer has the export’s id
  2. pendingWaiting its turn
  3. generatingYoPrint builds the file
  4. readyDownload the file
Downloading before the export is ready answers 404. An export can also end as failed.
  1. See which exports exist, and the columns and options each takes:

    GET List export types and their columns /v1/api/store/{team_slug}/data_export/definitions
  2. Start an export. For example, sales orders:

    POST Export sales orders in a date range to CSV /v1/api/store/{team_slug}/data_export/export_sales_order
    {
    "start_date": "2026-10-01T00:00:00Z",
    "end_date": "2026-12-31T23:59:59Z",
    "date_field": "issue_date",
    "idempotency_key": "so-export-2026-q4"
    }

    The answer is the export, with its id and status.

  3. Check it until status is ready. It moves from pending to generating, then to ready or failed.

    GET Get a data export /v1/api/store/{team_slug}/data_export/{id}
  4. Download the file, with the export’s id. The answer is the file itself, not JSON, so save it:

    GET Download a data export's file /v1/api/store/{team_slug}/data_export/{id}/download
    Terminal window
    curl -o sales-orders.csv \
    "https://secure.yoprint.com/v1/api/store/your-team/data_export/R38ZQ52Wx5meqn/download" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Accept: application/json" \
    -H "X-Yoprint-Decimal-Format: exact-v1"

The other exports work the same way: customers, invoices, invoice items, payments, purchase orders, taxes, simple products and variant products.

POST Export all customers to CSV /v1/api/store/{team_slug}/data_export/export_customer POST Export invoices in a date range to CSV /v1/api/store/{team_slug}/data_export/export_invoice POST Export payments and refunds in a date range to CSV /v1/api/store/{team_slug}/data_export/export_payment_list
  • Exports over a date range need start_date and end_date, with the end on or after the start. The sales order export also needs date_field, the order date the range applies to: issue_date, deposit_due, due_date, ship_due_date, cust_due_date or start_date.
  • columns picks the columns, from the export’s definition.
  • idempotency_key, up to 100 characters, makes the start safe to retry: the same key returns the same export instead of starting another. After a failure to queue, or an expired attempt, the same key queues it again. See Retries and duplicates.
  • Downloading before the export is ready answers 404.

A team can run 3 exports at once, and one of each kind. See Limits. To list your team’s exports:

GET List data exports /v1/api/store/{team_slug}/data_export

Some lists come straight back as a CSV file, without queueing. They take a date range:

POST Export sales orders as CSV /v1/api/store/{team_slug}/sales_order/export POST Export purchase orders by issue date /v1/api/store/{team_slug}/purchase_order/export
{ "start_date": "2026-11-01T00:00:00Z", "end_date": "2026-11-30T23:59:59Z" }

They don’t always answer with a file:

  • With "list_only": true, the rows come back as JSON instead, and an empty range answers an empty data list.
  • Without list_only, when nothing matches the date range, the answer is JSON 422 (sales_order_export_error or purchase_order_export_error), not an empty file.

Check the status and Content-Type before you save the body.

PDFs and printable files for chosen records:

POST Download invoices as one PDF /v1/api/store/{team_slug}/invoice/export_pdf POST Download job details (PDF) /v1/api/store/{team_slug}/job/export_job_detail POST Download packing slips (PDF) /v1/api/store/{team_slug}/shipment/export_packing_slip

These answer with the file itself, not JSON. Save the response body.

The public API imports one kind of CSV file: service pricing, a decoration service’s price table. An import either replaces the prices of a service you have (target_mode existing_service), or creates a new service with those prices (create).

  1. Download an example file to fill in:

    PUT Download the service pricing CSV template /v1/api/store/{team_slug}/csv/template/service_pricing
    qty/type,1 Color,2 Colors
    1,12.50,15.00
    24,8.00,10.00
    • The file: a UTF-8 .csv, at most 6,240 KB and 600 data rows.
    • Headers: exactly qty/type first, then one column per option, such as 1 Color.
    • Rows: one price break each, starting with its quantity. The first row’s is 1, and no quantity repeats.
    • Prices: every cell has one, a decimal number with at most 3 decimal places (12.50), or two separated by a bar, first|additional (12.50|9.00).
    • Writing numbers: a digit before the point (0.50, not .50), and no leading or trailing spaces. See Money and quantities.
  2. Upload it as a form (multipart/form-data, not JSON):

    POST Import a service's price table from CSV /v1/api/store/{team_slug}/imports/csv

    To replace an existing service’s prices:

    Terminal window
    curl https://secure.yoprint.com/v1/api/store/your-team/imports/csv \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Accept: application/json" \
    -H "X-Yoprint-Decimal-Format: exact-v1" \
    -F entity_type=service_pricing \
    -F target_mode=existing_service \
    -F service_id=V4keXwwxMQyXw7 \
    -F file=@service-pricing.csv

    To create a new service instead, send target_mode=create with its name, allow_cust_loc (1 or 0), pricing_type (single, additional or single_flat), and at least one print location in locations:

    Terminal window
    curl https://secure.yoprint.com/v1/api/store/your-team/imports/csv \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Accept: application/json" \
    -H "X-Yoprint-Decimal-Format: exact-v1" \
    -F entity_type=service_pricing \
    -F target_mode=create \
    -F "name=Screen print, 1 color" \
    -F allow_cust_loc=1 \
    -F pricing_type=single \
    -F "locations[0][id]=BkzhmfgkK2HFTs" \
    -F file=@service-pricing.csv

    Location ids come from your team’s print locations:

    GET List service locations /v1/api/store/{team_slug}/service_location

    No public operation lists services, so take an existing service’s id from a job’s services.

  3. Read the answer. The import runs while you wait, and the answer is the finished import. It’s all or nothing:

    • 422: the file broke a rule. The answer names the first problem found (with its line, for a row problem), and nothing is saved.
    • 500 ({ "message": "Server Error" }), also saving nothing: a price or quantity written like .50 or with a leading space, or a second upload for the same service (or the same new service name) that waited 45 seconds while the first was still running.

    Fix the file, or wait, and upload it again.

    To read an import again later:

    GET Get an import job /v1/api/store/{team_slug}/imports/{hash_id}

Replacing an existing service’s prices replaces its whole price table: options and price breaks missing from the file are removed. Service pricing imports never create a file of failed rows, so the error-file operation answers 404 for them.

  • CSV cell errors stop the whole import. Prices must be decimal numbers with at most 3 decimal places (such as 12.50). A cell with an invalid price, missing value, duplicate quantity, or more than 3 decimal places answers 422 with the line number and saves nothing. Formatting traps that cause 500 server errors: writing .50 without a leading 0, or including spaces around numbers.
  • Upload and request errors. Missing required parameters (service_id for existing_service, or name, pricing_type, allow_cust_loc and locations for create) fails with 422. Uploading while another import runs on the same service can time out with 500 after 45 seconds. Service pricing imports never create a file of failed rows. Downloading one answers 404.
  • Downloads aren’t JSON, until they fail. Export downloads, CSVs and PDFs answer with the file, but an error, or a quick export with nothing in range, answers JSON. Check the status first.
  • Wait for ready. A download before then answers 404. That doesn’t mean the export is lost.
  • One of each kind at a time. Starting a second sales order export while one runs answers 422 with duplicate_report.
  • Uploads are forms. The CSV import takes multipart/form-data, not JSON.
  • Dates are UTC. A range that should cover whole days in the shop’s timezone has to be converted.