Purchase the user's artwork
When a user purchases a print of their artwork, a partner must purchase the print-quality version of the artwork from Canva. The partner can then print the artwork and send it to the customer.
Step 1: Get the required order details
When a user purchases a print of their artwork, a partner must provide Canva with details about the order, such as the price of each item in the order. Canva uses this data to verify the revenue a partner owes. You can find the list of required properties in the API reference.
For this tutorial, pass placeholder amounts into the "cart" view:
app.get("/cart", async (request, response) => {response.render("cart", {artworkId: request.query.artworkId,artworkTitle: request.query.artworkTitle,previewImageSrc: request.query.previewImageSrc,order: "OR_12345672",item: "IT_12345672-003",sku: "PS034509",quantity: 5,currency: "USD",grossAmount: 65.5,discountAmount: 6.55,netAmount: 58.95,});});
Then render these values in the view:
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><metaname="viewport"content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover"/><title>Shopping cart</title></head><body><h1>Shopping cart</h1><h2>Order #<%= order %></h2><table><thead><tr><td>Item ID</td><td>Product SKU</td><td>Artwork ID</td><td>Artwork title</td><td>Preview</td><td>Quantity</td><td>Price (per item)</td></tr></thead><tbody><tr><td><%= item %></td><td><%= sku %></td><td><%= artworkId %></td><td><%= artworkTitle %></td><td><a href="<%= previewImageSrc %>">Click here</a></td><td><%= quantity %></td><td>$<%= grossAmount %> <%= currency %></td></tr></tbody></table><p>Price (with discounts): $<%= netAmount * quantity %> <%= currency %></p></body></html>
Step 2: Create an order form
To simulate the ordering of a print, add a form to the cart.ejs
file:
<form method="POST" action="/process-order"><input type="hidden" name="artworkId" value="<%= artworkId %>" /><input type="hidden" name="currency" value="<%= currency %>" /><input type="hidden" name="discountAmount" value="<%= discountAmount %>" /><input type="hidden" name="grossAmount" value="<%= grossAmount %>" /><input type="hidden" name="item" value="<%= item %>" /><input type="hidden" name="netAmount" value="<%= netAmount %>" /><input type="hidden" name="order" value="<%= order %>" /><input type="hidden" name="quantity" value="<%= quantity %>" /><input type="hidden" name="sku" value="<%= sku %>" /><button>Confirm order</button></form>
When a user submits this form, it sends a POST
request to /process-order
, which is an endpoint that doesn't exist (yet). The hidden fields contain the data that Canva requires for processing orders.
Step 3: Purchase the artwork from Canva
In the server.js
file, create a route that receives POST
requests:
app.post("/process-order", async (request, response) => {// code goes here});
In this route, send a POST
request to the following endpoint:
https://api.canva.com/_tpi/partnership/<partner_id>/artworks/<artwork_id>
In this request:
- Replace
<partner_id>
with the Partner ID. - Replace
<artwork_id>
with the ID of the user's artwork. - Set the
Authorization
header to the Artwork API secret. - Include a
purchaseConfirmation
object in the body. The object must contain the data that Canva requires to process the order, the SKU of each product.
This example destructures the required data from the request body and uses the axios library to send a request:
app.post("/process-order", async (request, response) => {// Get the required data from the incoming request bodyconst {artworkId,currency,discountAmount,grossAmount,item,netAmount,order,quantity,sku,} = request.body;// Send a request to Canvaconst { data } = await axios.request({baseURL: "https://api.canva.com",url: `/_tpi/partnership/${process.env.PARTNER_ID}/artworks/${artworkId}`,method: "post",headers: {Authorization: process.env.ARTWORK_API_SECRET,},data: {purchaseConfirmation: {currency,discountAmount: parseFloat(discountAmount),grossAmount: parseFloat(grossAmount),item,netAmount: parseFloat(netAmount),order,quantity: parseInt(quantity),sku,},},});// Log the resultsconsole.log(data);});
The response body contains a productionFile
property that contains the URL of the print-quality artwork.
Step 4: Print the user's artwork
A real integration should download the print-quality version of the user's artwork and send it off for printing. For this tutorial, simply redirect users to the print-quality artwork:
// Redirect users to the print-quality artworkresponse.redirect(data.productionFile);
Example
src/views/cart.ejs
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><metaname="viewport"content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover"/><title>Shopping cart</title></head><body><h1>Shopping cart</h1><h2>Order #<%= order %></h2><table><thead><tr><td>Item ID</td><td>Product SKU</td><td>Artwork ID</td><td>Artwork title</td><td>Preview</td><td>Quantity</td><td>Price (per item)</td></tr></thead><tbody><tr><td><%= item %></td><td><%= sku %></td><td><%= artworkId %></td><td><%= artworkTitle %></td><td><a href="<%= previewImageSrc %>">Click here</a></td><td><%= quantity %></td><td>$<%= grossAmount %> <%= currency %></td></tr></tbody></table><p>Price (with discounts): $<%= netAmount * quantity %> <%= currency %></p><form method="POST" action="/process-order"><input type="hidden" name="artworkId" value="<%= artworkId %>" /><input type="hidden" name="currency" value="<%= currency %>" /><inputtype="hidden"name="discountAmount"value="<%= discountAmount %>"/><input type="hidden" name="grossAmount" value="<%= grossAmount %>" /><input type="hidden" name="item" value="<%= item %>" /><input type="hidden" name="netAmount" value="<%= netAmount %>" /><input type="hidden" name="order" value="<%= order %>" /><input type="hidden" name="quantity" value="<%= quantity %>" /><input type="hidden" name="sku" value="<%= sku %>" /><button>Confirm order</button></form></body></html>
src/views/index.ejs
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><metaname="viewport"content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover"/><title>Print Partnership Example</title><script src="https://sdk.canva.com/partnership.js"></script><style type="text/css">body,html {margin: 0;}#container {height: 100vh;}</style></head><body><div id="container"></div><script type="text/javascript">(async () => {const api = await Canva.Partnership.initialize({apiKey: "<%= partnerApiKey %>",container: document.getElementById("container"),autoAuthToken: "<%= autoAuthToken %>",});const onBackClick = () => {console.log("You clicked the 'Back' button in the Canva editor's header.");};const onArtworkCreate = (opts) => {// Create a query stringconst params = new URLSearchParams();// Add opts (artworkId, etc) to query stringObject.keys(opts).forEach((key) => {params.append(key, opts[key]);});// Redirect the user to shopping cartwindow.location.href = `/cart?${params.toString()}`;};const onProductSelect = (opts) => {api.createDesign({...opts,onBackClick,onArtworkCreate,});};api.showCatalog({onProductSelect,});})();</script></body></html>
src/server.js
require("dotenv").config();const axios = require("axios");const express = require("express");const jwt = require("jwt-simple");const app = express();app.set("views", "./src/views");app.set("view engine", "ejs");app.use(express.json());app.use(express.urlencoded({ extended: true }));app.get("/", async (request, response) => {// Get the current timeconst now = Math.floor(new Date().getTime() / 1000);// Create a payloadconst payload = {iss: process.env.PARTNER_API_KEY,sub: "12345",iat: now,exp: now + 60 * 30,};// Calculate the autoAuthTokenconst autoAuthToken = jwt.encode(payload, process.env.PARTNER_API_SECRET);response.render("index", {autoAuthToken,partnerApiKey: process.env.PARTNER_API_KEY,});});app.get("/cart", async (request, response) => {response.render("cart", {artworkId: request.query.artworkId,artworkTitle: request.query.artworkTitle,previewImageSrc: request.query.previewImageSrc,order: "OR_12345672",item: "IT_12345672-003",sku: "PS034509",quantity: 5,currency: "USD",grossAmount: 65.5,discountAmount: 6.55,netAmount: 58.95,});});app.post("/process-order", async (request, response) => {// Get the required data from the incoming request bodyconst {artworkId,currency,discountAmount,grossAmount,item,netAmount,order,quantity,sku,} = request.body;// Send a request to Canvaconst { data } = await axios.request({baseURL: "https://api.canva.com",url: `/_tpi/partnership/${process.env.PARTNER_ID}/artworks/${artworkId}`,method: "post",headers: {Authorization: process.env.ARTWORK_API_SECRET,},data: {purchaseConfirmation: {currency,discountAmount: parseFloat(discountAmount),grossAmount: parseFloat(grossAmount),item,netAmount: parseFloat(netAmount),order,quantity: parseInt(quantity),sku,},},});// Redirect users to the print-quality artworkresponse.redirect(data.productionFile);});app.listen(process.env.PORT || 3000);