---
title: "Receiving print-ready files | Customer&#x27;s Canvas Hub"
canonical: "https://customerscanvas.com/docs/hub/dev-center/scenarios/online-store/receiving-print-ready-files/"
---

# Receiving print-ready files

> Let's say your customers have created personalized designs using a Customer's Canvas editor and placed an order on your online store. If your store is based on one of the e-commerce platforms we support (like Shopify, BigCommerce, WooCommerce, Magento, or nopCommerce), or if you've implemented a [custom storefront integration](https://customerscanvas.com/docs/hub/dev-center/scenarios/online-store.md), a *project* is created once the order is placed. You can easily access the project in the Customer's Canvas BackOffice app and download the print files from it.

However, downloading print files manually isn't always an option. For instance, if you don't handle order fulfillment in-house and instead use an API to send orders to your printing company.

In such a scenario, you can use the Customer's Canvas API to automatically download print files (or, speaking more widely, *artifacts*, which can include additional files if required) for completed orders. This article provides instructions on how to do so.

## Assumptions

Here are some assumptions that we will make for this guide:

1. Your application can receive information about orders from your e-commerce platform, and your app can differentiate between new orders and orders you have already processed.

   :::note
   For example, if you're using Shopify, your app may subscribe to the `orders/create` webhook. Alternatively, you could request all new orders once per day and mark them as processed once you've downloaded the order artifacts (print files).
   :::

2. An online store is integrated with Customer's Canvas, and you have its `storefrontId` (explained further).
3. The processing pipelines are properly configured for the products you want to process.
4. Your objective is to download all artifacts for the selected orders.

## How we are going to achieve this goal

The diagram below illustrates the flow initiated by an e-commerce platform when a user completes an order for a product with Customer's Canvas data.

```mermaid
flowchart TD
  subgraph Processing pipeline
    task1(Task 1) --> task2(Task 2)
    task2 --> otherTasks(...)
    otherTasks --> finalTask(Final task) 
  end
  subgraph E-commerce Platform
    order(Order completed) 
  end
  subgraph Customer's Canvas
    order -- order creation webhook --> project(Project created)
    project -- starts processing pipeline --> task1
    finalTask -- save artifact --> artifact(Artifacts saved\nin Asset Storage)
  end
```

When a user completes an order for a product with Customer's Canvas data, the e-commerce platform triggers the order creation webhook. Customer's Canvas handles this webhook and creates a project record, which starts the processing pipeline. Since the processing pipeline works asynchronously, it may take some time to complete all steps. However, once finished, the artifacts created by its tasks are saved in Asset Storage.

As soon as the project is created, Customer's Canvas saves the order ID and its number as the project metadata. This allows your app to request projects related to your orders. Once you have the project information, you can find the processing pipeline associated with it. Only one processing pipeline per project may exist. A pipeline is not created immediately with a project, but any delay is typically quite small.

The processing pipeline can have several statuses, such as pending or in progress. You need to implement a polling scheme and repeat the request at a certain time interval until the pipeline becomes complete. Note that the pipeline may fail, and in this case, you need to stop polling. You should decide what your app should do in such cases, such as saving this information to a log or attempting to restart it.

When the pipeline is successfully completed, all relevant print files and other artifacts become available to download.

The following sequence diagram illustrates the process.

```mermaid
sequenceDiagram
	participant C as Customer's Canvas
	participant A as Your App
	participant E as E-commerce Platform
	A ->> +E : Get new orders 	
	E ->> -A : New orders 	
	loop For each order
	A ->> +C : Get an order's project
	C ->> A : Project
	A ->> C : Get a project's pipeline
	C ->> A : Pipeline
	A ->> C : Get pipeline status
	C ->> A : Pending | Completed <br/>| Failed
	Note over A: Once Pipeline is Completed
	A ->> C : Get artifacts
	C ->> A : List of URLs
	loop For each artifact
	A ->> C : Download artifact
	C ->> -A : Artifact binary (e.g. PDF)
	end
	A ->> E : Tag order as done
	end
```

## Using the API

This guide assumes that you are familiar with the principles of how you should use the Customer's Canvas API. If not, we recommend that you take a look at these articles first.

- [API overview and information about supported API Client libraries](https://customerscanvas.com/docs/hub/dev-center/api.md)
- [Guide on how you can properly integrate the C# API Client library to your .NET app](https://customerscanvas.com/docs/hub/dev-center/api/clients/cs-api-client.md)

### Authenticating your app

Before we start, make sure that your app has credentials to make API calls. For the scenario described above, the most relevant authentication scheme is via **Client Credentials**. 

Register your app in your tenant and implement the authentication in the [Authentication](https://customerscanvas.com/docs/hub/dev-center/api/auth.md) article.

### Determining your storefrontId

Customer's Canvas allows for integrating a single tenant with multiple _storefronts_ (i.e., online stores) simultaneously. For example, you may have two Shopify stores with different domains for different products. Or, you may have one store based on WooCommerce and another one on BigCommerce.

When you work with projects, you need to know the `storefrontId`, which allows you to distinguish one store from another. It is especially important considering that the uniqueness of the order numbers between different online stores is not guaranteed. 

To determine the `storefrontId`, in your Customer's Canvas account, go to **Settings** > **Integrations**. The `storefrontId` is in the left column.

![Settings -> Integrations, storefrontId](./images/storefront-id.png)

### Searching projects for an order

You can use the endpoint [`GET /api/storefront/v1/projects`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/projects/GetAll) to receive a list of all projects. You need to provide at least two arguments to achieve our goal: 

1. `storefrontId` - obtained as explained above.
2. `orderId` - an ID of an order you need to process.

Let's assume that the `storefrontId` is 42 and the `orderId` is 123.

**cURL**

```bash
curl -X \
  GET "https://api.customerscanvashub.com/api/storefront/v1/projects?orderId=123&storefrontId=42" \
  -H  "accept: text/plain"\
  -H  "Authorization: Bearer <TOKEN>"
```

**HTTP**

```
GET https://api.customerscanvashub.com/api/storefront/v1/projects?orderId=123&storefrontId=42
```

**C#**

```csharp
var storefrontId = 42; // Put your real storefrontId here
var order = "123"; // Put your real order ID here
var projectsPagedList = await storefrontApiClient.GetAllAsync(storefrontId, orderId: order);
```

**TS**

```typescript
var storefrontId = 42; // Put your real storefrontId here
var orderId = "123"; // Put your real order ID here
var projectsPagedList = await _storefrontApiClient.getAll(storefrontId, null, null, null, null, null, null, null, null, orderId);
```

**PHP**

```php
$storefrontId = 42; // Put your real storefrontId here
$orderId = "123"; // Put your real order ID here
$projectsPagedList = $storefrontApiClient->projectsGetAll($storefrontId, null, null, null, null, null, null, null, null, $orderId, null);
```

It returns a structure containing a list of project items filtered by this order ID. Note that it is a normal scenario when a single order includes multiple projects. For example, if an order consists of several line items and these line items represent products associated with Customer's Canvas, a project per each line item is created.

You need to use the `id` of each project in this list as explained further.

### Getting a project's artifacts directly

To simplify the process, we have introduced a dedicated endpoint that enables you to receive artifacts directly from a project without worrying about the processing pipeline. You can access this endpoint at [`GET /api/storefront/v1/projects/{id}/processing-results`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/projects/GetProjectProcessingResults) by passing the ID of each project returned in the previous step.

For example, if the project ID is 4567, the API call may look like this. 

**cURL**

```bash
curl -X \
  GET "https://api.customerscanvashub.com/api/storefront/v1/projects/4567/processing-results" \
  -H  "accept: text/plain" \
  -H  "Authorization: Bearer <TOKEN>"
```

**HTTP**

```
GET https://api.customerscanvashub.com/api/storefront/v1/projects/4567/processing-results
```

**C#**

```csharp
var projectId = 4567; // Set a real project ID here
var processingResults = await storefrontApiClient.GetProjectProcessingResultsAsync(projectId);
```

**TS**

```typescript
var projectId = 4567; // Put your real project ID here
var processingResults = await _storefrontApiClient.getProjectProcessingResults(projectId);
```

**PHP**

```php
$projectId = 4567; // Put your real project ID here
$processingResults = $storefrontApiClient->projectsGetProjectProcessingResults($projectId);
```

Once you receive the processing results, you need to check the `status` field, which can have one of four values: `Pending`, `InProgress`, `Completed`, or `Failed`. 

- If the status is `Pending` or `InProgress`, you should wait and retry after some interval, such as several minutes (minimum 60 seconds). 
- If the status is `Failed`, refer to the `statusDescription` field for additional details. 
- If the status is `Completed`, the artifacts are ready, and you can retrieve them from the `outputFileDetails` property.

When processing the `outputFileDetails`, keep in mind that depending on the processing pipeline, the results may include more than one file. For example, it may include a print-ready PDF file, a reference preview, and a JSON description of the order. It may also include multiple PDF files for a VDP scenario.

One important parameter to consider is whether artifacts can be downloaded using a direct link without authentication. An author of a processing pipeline may control whether artifacts are available anonymously or not. Your app can determine this by checking the `anonymousAccess` flag. If the flag is `true`, you can download the artifact using the `url` property. If it is not `true`, you will need to use the [`GET /api/storage/v1/artifacts/{id}/file`](https://customerscanvas.com/docs/hub/dev-center/api/asset-storage.md#tag/artifacts/GetFile) endpoint of the [Asset Storage API](https://customerscanvas.com/docs/hub/dev-center/api/asset-storage.md), as explained later in this article.

These steps should be sufficient to achieve your goal of downloading print files for an order. However, if you need more control over the rendering process for any reason, you may want to explore other capabilities of the API.

### Restarting failed pipelines

There are several reasons why a pipeline may have a `Failed` status. Some of these reasons may be temporary, in which case you may want to retry the pipeline execution. There are two operations you can use to retry a failed pipeline:

- Resume [`POST /api/storefront/v1/projects/{id}/resume-processing`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/projects/ResumeProjectProcessing): This operation continues the pipeline from the point of the last failed task.
- Restart [`POST /api/storefront/v1/projects/{id}/restart-processing`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/projects/RestartProjectProcessing): This operation restarts the pipeline from the first task.

We recommend using the Resume operation to recover a failed pipeline to avoid redoing operations that have already succeeded, which can reduce overhead. Additionally, certain tasks should not be repeated without a good reason. For example, if a task purchases a photo from a stock service, and the pipeline fails on a subsequent task, restarting the pipeline would cause a second purchase of the item, which has already been paid for.

However, the Restart operation is useful in situations where you need to regenerate all temporary artifacts from scratch, such as when editing a personalized design after the user has submitted it.

When retrying a failed pipeline, it is important to use a reasonable delay between attempts. Ideally, this delay should be several minutes and should not be less than one minute.

To resume a failed pipeline, use the following API call.

**cURL**

```bash
curl -X \
  POST "https://api.customerscanvashub.com/api/storefront/v1/projects/4567/resume-processing" \
  -H  "accept: text/plain" \
  -H  "Authorization: Bearer <TOKEN>" \
  -d  ""
```

**HTTP**

```
POST https://api.customerscanvashub.com/api/storefront/v1/projects/4567/resume-processing
```

**C#**

```csharp
var projectId = 4567; // Set a real project ID 
await storefrontApiClient.ResumeProjectProcessingAsync(projectId);
```

**TS**

```typescript
var projectId = 4567; // Put your real project ID here
await _storefrontApiClient.resumeProjectProcessing(projectId);
```

**PHP**

```php
$projectId = 4567; // Put your real project ID here
$storefrontApiClient->projectsResumeProjectProcessing($projectId);
```

A Restart operation is called in a similar manner.

**cURL**

```bash
curl -X \
  POST "https://api.customerscanvashub.com/api/storefront/v1/projects/4567/restart-processing" \
  -H  "accept: text/plain" \
  -H  "Authorization: Bearer <TOKEN>" \
  -d  ""
```

**HTTP**

```
POST https://api.customerscanvashub.com/api/storefront/v1/projects/4567/restart-processing
```

**C#**

```csharp
var projectId = 4567; // Set a real project ID 
await storefrontApiClient.RestartProjectProcessingAsync(projectId);
```

**TS**

```typescript
var projectId = 4567; // Put your real project ID here
await _storefrontApiClient.restartProjectProcessing(projectId);
```

**PHP**

```php
$projectId = 4567; // Put your real project ID here
$storefrontApiClient->projectsRestartProjectProcessing($projectId);
```

### Getting a list of artifacts

If you need to get a list of artifacts by pipeline ID, you can use the [`GET /api/storage/v1/artifacts`](https://customerscanvas.com/docs/hub/dev-center/api/asset-storage.md#tag/artifacts/GetAll) endpoint of the [Asset Storage API](https://customerscanvas.com/docs/hub/dev-center/api/asset-storage.md). This is useful in situations where you need to get some extended details about them compared to the approach with [`GET /api/storefront/v1/projects/{id}/processing-results`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/projects/GetProjectProcessingResults).

To use the endpoint, pass the pipeline ID as a `group` parameter. This result will show only the artifacts that were generated as part of the specified pipeline. You can also filter out all temporary artifacts by specifying the type as Final.

For example, if you wanted to get a list of all final artifacts generated by a pipeline with ID 12345, you could make the following API call:

**cURL**

```bash
curl -X \
  GET "https://api.customerscanvashub.com/api/storage/v1/artifacts?group=12345&type=Final" \
  -H  "accept: text/json"\
  -H  "Authorization: Bearer <TOKEN>"
```

**HTTP**

```
GET https://api.customerscanvashub.com/api/storage/v1/artifacts?group=12345&type=Final
```

**C#**

```csharp
var pipelineId = 12345; // Set a real pipeline ID 
var artifacts = await artifactsApiClient.GetAllAsync(group: pipelineId, type: ArtifactType.Final);
```

**TS**

```typescript
var pipelineId = 12345; // Put your real pipeline ID here
var artifacts = await _artifactsApiClient.getAll(pipelineId, null, ArtifactType.Final);
```

**PHP**

```php
$pipelineId = 12345; // Put your real pipeline ID here
$artifacts = $assetStorageApiClient->artifactsGetAll($pipelineId, null, Aurigma\AssetStorage\Model\ArtifactType::_FINAL);
```

This would return a list of all final artifacts generated by the specified pipeline.

### Downloading artifacts

When using the [`GET /api/storage/v1/artifacts`](https://customerscanvas.com/docs/hub/dev-center/api/asset-storage.md#tag/artifacts/GetAll) endpoint to retrieve artifacts, as explained above, the output structure contains additional fields, such as `size` and `lastModified`, in addition to the ones returned by [`GET /api/storefront/v1/projects/{id}/processing-results`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/projects/GetProjectProcessingResults).

To download the results, you can simply use the [`GET /api/storage/v1/artifacts/{id}/file`](https://customerscanvas.com/docs/hub/dev-center/api/asset-storage.md#tag/artifacts/GetFile) endpoint and provide the artifact ID. If needed, you can include the `attachment` flag to control whether the `Content-Disposition` header with the file name should be included in the API response or not.

Let's see how you can get an artifact with ID = 98765 with the attachment mode enabled.

**cURL**

```bash
curl -X \
  GET "https://api.customerscanvashub.com/api/storage/v1/artifacts/98765/file?attachment=true" \
  -H  "accept: application/octet-stream" \
  -H  "Authorization: Bearer <TOKEN>"
```

**HTTP**

```
GET https://api.customerscanvashub.com/api/storage/v1/artifacts/98765/file?attachment=true
```

**C#**

```csharp
var artifactId = 98765; // Set a real artifact ID 
var file = await artifactsApiClient.GetFileAsync(artifactId, true);
```

**TS**

```typescript
var artifactId = 98765; // Put your real artifact ID here
var file = await _artifactsApiClient.getFile(artifactId, true);
```

**PHP**

```php
$artifactId = 98765; // Put your real artifact ID here
$file = $assetStorageApiClient->artifactsGetFile($artifactId, true);
```

If the processing pipeline author has enabled the ability to download artifacts via a direct link, you can access these files more easily by using the `url` property without requiring authentication. To ensure that direct URLs are available, check if the `anonymousAccess` property is set to `true`.

## Conclusion

In this article, we have discussed the flow required to download print files and other artifacts for completed e-commerce orders, which is a crucial task in integrating Customer's Canvas with order fulfillment systems.

We have determined that the most efficient way to achieve this goal is by utilizing the [`GET /api/storefront/v1/projects/{id}/processing-results`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/projects/GetProjectProcessingResults) endpoint. However, we have also explored an additional endpoint that performs other tasks, such as recovering failed pipelines, checking the project status, and receiving the binary content of the artifacts.

By following the guidelines provided in this article, you can easily integrate Customer's Canvas into your e-commerce system and streamline your order fulfillment process.
