Create design merge job

This API is currently provided as a preview. Be aware of the following:

  • There might be unannounced breaking changes.
  • Any breaking changes to preview APIs won't produce a new API version.
  • Public integrations that use preview APIs will not pass the review process, and can't be made available to all Canva users.

Starts a new asynchronous job to merge design pages by applying page operations (such as insert, move, or delete) to produce a new design or modify an existing one.

When the job completes successfully, the job result includes metadata for the created or updated design.

For more information on the workflow for using asynchronous jobs, see API requests and responses. You can check the status and get the results of jobs created with this API using the Get design merge job API.

HTTP method and URL path

POST https://api.canva.com/rest/v1/merges

This operation is rate limited to 100 requests per minute for each user of your integration.

Authentication and authorization

This endpoint requires a valid access token that acts on behalf of a user.

Scopes

The access token must have all the following scopes (permissions):

  • design:content:write
  • design:meta:read

Header parameters

Authorizationstring
Required

Provides credentials to authenticate the request, in the form of a Bearer token.

For example: Authorization: Bearer {token}

Content-Typestring
Required

Indicates the media type of the information sent in the request. This must be set to application/json.

For example: Content-Type: application/json

Body parameters

Creates a new design by inserting pages from other designs.

typestring
Required

The type of merge job to create.

Available values: The only valid value is create_new_design.

operationsDesignMergeOperation[]
Required

For this job type, only insert operations are supported.

Minimum items: 1

Maximum items: 500

Inserts pages from a source design into the target design.

typestring
Required

The type of merge operation.

Available values: The only valid value is insert_pages.

sourceMergeSourceForInsertPagesOperation
Required

A design source from which pages are inserted.

typestring
Required

The type of source to insert pages from.

Available values: The only valid value is design.

design_idstring
Required

The ID of the source design.

page_numbersinteger[]
Optional

One-based page numbers to insert from the source design. If omitted, all pages from the design are inserted.

Minimum items: 1

after_page_numberinteger
Optional

Insert after this one-based page number in the evolving target layout. Use 0 to insert at the beginning, and the default is inserting at the end (append).

Moves pages within the target design to a new position.

typestring
Required

The type of merge operation.

Available values: The only valid value is move_pages.

from_page_numbersinteger[]
Required

One-based number of the pages to move (evaluated at the time this operation runs). Pages are moved in order.

Minimum items: 1

to_after_page_numberinteger
Required

Destination position: insert the moved pages after this one-based page number. Use 0 to move to the beginning.

Deletes pages from the target design.

typestring
Required

The type of merge operation.

Available values: The only valid value is delete_pages.

page_numbersinteger[]
Required

One-based numbers of the pages to delete (evaluated at the time this operation runs). Pages are deleted in reverse order to maintain page numbers.

Minimum items: 1

titlestring
Required

Title for the new design.

Minimum length: 1

Maximum length: 255

Modifies an existing design by inserting, moving, or deleting pages.

typestring
Required

The type of merge job to create.

Available values: The only valid value is modify_existing_design.

design_idstring
Required

The ID of the design to modify.

operationsDesignMergeOperation[]
Required

Supports insert, move, and delete operations.

Minimum items: 1

Maximum items: 500

Inserts pages from a source design into the target design.

typestring
Required

The type of merge operation.

Available values: The only valid value is insert_pages.

sourceMergeSourceForInsertPagesOperation
Required

A design source from which pages are inserted.

typestring
Required

The type of source to insert pages from.

Available values: The only valid value is design.

design_idstring
Required

The ID of the source design.

page_numbersinteger[]
Optional

One-based page numbers to insert from the source design. If omitted, all pages from the design are inserted.

Minimum items: 1

after_page_numberinteger
Optional

Insert after this one-based page number in the evolving target layout. Use 0 to insert at the beginning, and the default is inserting at the end (append).

Moves pages within the target design to a new position.

typestring
Required

The type of merge operation.

Available values: The only valid value is move_pages.

from_page_numbersinteger[]
Required

One-based number of the pages to move (evaluated at the time this operation runs). Pages are moved in order.

Minimum items: 1

to_after_page_numberinteger
Required

Destination position: insert the moved pages after this one-based page number. Use 0 to move to the beginning.

Deletes pages from the target design.

typestring
Required

The type of merge operation.

Available values: The only valid value is delete_pages.

page_numbersinteger[]
Required

One-based numbers of the pages to delete (evaluated at the time this operation runs). Pages are deleted in reverse order to maintain page numbers.

Minimum items: 1

titlestring
Optional

Optional new title for the design.

Minimum length: 1

Maximum length: 255

Example request

Examples for using the /v1/merges endpoint:

curl --request POST 'https://api.canva.com/rest/v1/merges' \
--header 'Authorization: Bearer {token}' \
--header 'Content-Type: application/json' \
--data '{
"type": "create_new_design",
"operations": [
{
"type": "insert_pages",
"source": {
"type": "design",
"design_id": "DAFVztcvd9z",
"page_numbers": [
1,
2
]
},
"after_page_number": 2
},
{
"type": "move_pages",
"from_page_numbers": [
1,
3
],
"to_after_page_number": 2
},
{
"type": "delete_pages",
"page_numbers": [
2,
4
]
}
],
"title": "My merged design"
}'
SH
const fetch = require("node-fetch");
fetch("https://api.canva.com/rest/v1/merges", {
method: "POST",
headers: {
"Authorization": "Bearer {token}",
"Content-Type": "application/json",
},
body: JSON.stringify({
"type": "create_new_design",
"operations": [
{
"type": "insert_pages",
"source": {
"type": "design",
"design_id": "DAFVztcvd9z",
"page_numbers": [
1,
2
]
},
"after_page_number": 2
},
{
"type": "move_pages",
"from_page_numbers": [
1,
3
],
"to_after_page_number": 2
},
{
"type": "delete_pages",
"page_numbers": [
2,
4
]
}
],
"title": "My merged design"
}),
})
.then(async (response) => {
const data = await response.json();
console.log(data);
})
.catch(err => console.error(err));
JS
import java.io.IOException;
import java.net.URI;
import java.net.http.*;
public class ApiExample {
public static void main(String[] args) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.canva.com/rest/v1/merges"))
.header("Authorization", "Bearer {token}")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"type\": \"create_new_design\", \"operations\": [{\"type\": \"insert_pages\", \"source\": {\"type\": \"design\", \"design_id\": \"DAFVztcvd9z\", \"page_numbers\": [1, 2]}, \"after_page_number\": 2}, {\"type\": \"move_pages\", \"from_page_numbers\": [1, 3], \"to_after_page_number\": 2}, {\"type\": \"delete_pages\", \"page_numbers\": [2, 4]}], \"title\": \"My merged design\"}"))
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.body());
}
}
JAVA
import requests
headers = {
"Authorization": "Bearer {token}",
"Content-Type": "application/json"
}
data = {
"type": "create_new_design",
"operations": [
{
"type": "insert_pages",
"source": {
"type": "design",
"design_id": "DAFVztcvd9z",
"page_numbers": [
1,
2
]
},
"after_page_number": 2
},
{
"type": "move_pages",
"from_page_numbers": [
1,
3
],
"to_after_page_number": 2
},
{
"type": "delete_pages",
"page_numbers": [
2,
4
]
}
],
"title": "My merged design"
}
response = requests.post("https://api.canva.com/rest/v1/merges",
headers=headers,
json=data
)
print(response.json())
PY
using System.Net.Http;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://api.canva.com/rest/v1/merges"),
Headers =
{
{ "Authorization", "Bearer {token}" },
},
Content = new StringContent(
"{\"type\": \"create_new_design\", \"operations\": [{\"type\": \"insert_pages\", \"source\": {\"type\": \"design\", \"design_id\": \"DAFVztcvd9z\", \"page_numbers\": [1, 2]}, \"after_page_number\": 2}, {\"type\": \"move_pages\", \"from_page_numbers\": [1, 3], \"to_after_page_number\": 2}, {\"type\": \"delete_pages\", \"page_numbers\": [2, 4]}], \"title\": \"My merged design\"}",
Encoding.UTF8,
"application/json"
),
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
};
CSHARP
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
payload := strings.NewReader(`{
"type": "create_new_design",
"operations": [
{
"type": "insert_pages",
"source": {
"type": "design",
"design_id": "DAFVztcvd9z",
"page_numbers": [
1,
2
]
},
"after_page_number": 2
},
{
"type": "move_pages",
"from_page_numbers": [
1,
3
],
"to_after_page_number": 2
},
{
"type": "delete_pages",
"page_numbers": [
2,
4
]
}
],
"title": "My merged design"
}`)
url := "https://api.canva.com/rest/v1/merges"
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer {token}")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}
GO
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.canva.com/rest/v1/merges",
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => array(
'Authorization: Bearer {token}',
'Content-Type: application/json',
),
CURLOPT_POSTFIELDS => json_encode([
"type" => "create_new_design",
"operations" => [
[
"type" => "insert_pages",
"source" => [
"type" => "design",
"design_id" => "DAFVztcvd9z",
"page_numbers" => [
1,
2
]
],
"after_page_number" => 2
],
[
"type" => "move_pages",
"from_page_numbers" => [
1,
3
],
"to_after_page_number" => 2
],
[
"type" => "delete_pages",
"page_numbers" => [
2,
4
]
]
],
"title" => "My merged design"
])
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if (empty($err)) {
echo $response;
} else {
echo "Error: " . $err;
}
PHP
require 'net/http'
require 'uri'
url = URI('https://api.canva.com/rest/v1/merges')
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request['Authorization'] = 'Bearer {token}'
request['Content-Type'] = 'application/json'
request.body = <<REQUEST_BODY
{
"type": "create_new_design",
"operations": [
{
"type": "insert_pages",
"source": {
"type": "design",
"design_id": "DAFVztcvd9z",
"page_numbers": [
1,
2
]
},
"after_page_number": 2
},
{
"type": "move_pages",
"from_page_numbers": [
1,
3
],
"to_after_page_number": 2
},
{
"type": "delete_pages",
"page_numbers": [
2,
4
]
}
],
"title": "My merged design"
}
REQUEST_BODY
response = http.request(request)
puts response.read_body
RUBY

Success response

If successful, the endpoint returns a 200 response with a JSON body with the following parameters:

jobDesignMergeJob

The details of a design merge job.

idstring

The ID of the design merge job.

statusstring

Available values:

  • in_progress: The merge job is still running.
  • success: The merge job completed successfully.
  • failed: The merge job failed.
resultDesignMergeJobResult
Optional
designDesignSummary

Basic details about the design, such as the design's ID, title, and URL.

idstring

The design ID.

urlsDesignLinks

A temporary set of URLs for viewing or editing the design.

edit_urlstring

A temporary editing URL for the design. This URL is only accessible to the user that made the API request, and is designed to support return navigation workflows.

This is not a permanent URL, it is only valid for 30 days.

view_urlstring

A temporary viewing URL for the design. This URL is only accessible to the user that made the API request, and is designed to support return navigation workflows.

This is not a permanent URL, it is only valid for 30 days.

created_atinteger

When the design was created in Canva, as a Unix timestamp (in seconds since the Unix Epoch).

updated_atinteger

When the design was last updated in Canva, as a Unix timestamp (in seconds since the Unix Epoch).

titlestring
Optional

The design title.

urlstring
Optional

URL of the design.

thumbnailThumbnail
Optional

A thumbnail image representing the object.

widthinteger

The width of the thumbnail image in pixels.

heightinteger

The height of the thumbnail image in pixels.

urlstring

A URL for retrieving the thumbnail image. This URL expires after 15 minutes. This URL includes a query string that's required for retrieving the thumbnail.

page_countinteger
Optional

The total number of pages in the design. Some design types don't have pages (for example, Canva docs).

errorDesignMergeError
Optional

If the merge job fails, this object provides details about the error.

codestring

Available values:

  • thumbnail_generation_error
  • merge_error
  • create_design_error
  • modify_design_error
messagestring

A human-readable description of what went wrong.

Example response

{
"job": {
"id": "a7by3wd-abc123",
"status": "in_progress",
"result": {
"design": {
"id": "DAFVztcvd9z",
"title": "My summer holiday",
"url": "https://www.canva.com/design/DAFVztcvd9z/edit",
"thumbnail": {
"width": 595,
"height": 335,
"url": "https://document-export.canva.com/Vczz9/zF9vzVtdADc/2/thumbnail/0001.png?<query-string>"
},
"urls": {
"edit_url": "https://www.canva.com/api/design/eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiZXhwaXJ5IjoxNzQyMDk5NDAzMDc5fQ..GKLx2hrJa3wSSDKQ.hk3HA59qJyxehR-ejzt2DThBW0cbRdMBz7Fb5uCpwD-4o485pCf4kcXt_ypUYX0qMHVeZ131YvfwGPIhbk-C245D8c12IIJSDbZUZTS7WiCOJZQ.sNz3mPSQxsETBvl_-upMYA/edit",
"view_url": "https://www.canva.com/api/design/eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiZXhwaXJ5IjoxNzQyMDk5NDAzMDc5fQ..GKLx2hrJa3wSSDKQ.hk3HA59qJyxehR-ejzt2DThBW0cbRdMBz7Fb5uCpwD-4o485pCf4kcXt_ypUYX0qMHVeZ131YvfwGPIhbk-C245D8c12IIJSDbZUZTS7WiCOJZQ.sNz3mPSQxsETBvl_-upMYA/view"
},
"created_at": 1377396000,
"updated_at": 1692928800,
"page_count": 3
}
},
"error": {
"code": "thumbnail_generation_error",
"message": "The merge job failed due to an internal error."
}
}
}
JSON

Error responses

400 Bad Request

codestring

A short string indicating what failed. This field can be used to handle errors programmatically. For a complete list of error codes, see Error responses.

messagestring

A human-readable description of what went wrong.

Example error response

{
"code": "invalid_request",
"message": "Invalid merge job type: {jobType}"
}
JSON

403 Forbidden

codestring

A short string indicating what failed. This field can be used to handle errors programmatically. For a complete list of error codes, see Error responses.

messagestring

A human-readable description of what went wrong.

Example error response

{
"code": "permission_denied",
"message": "Not allowed to access design '{designId}'"
}
JSON

404 Not Found

codestring

A short string indicating what failed. This field can be used to handle errors programmatically. For a complete list of error codes, see Error responses.

messagestring

A human-readable description of what went wrong.

Example error response

{
"code": "not_found",
"message": "Design '{designId}' not found"
}
JSON

413 Request Entity Too Large

codestring

A short string indicating what failed. This field can be used to handle errors programmatically. For a complete list of error codes, see Error responses.

messagestring

A human-readable description of what went wrong.

Example error response

{
"code": "bad_request_params",
"message": "The request size exceeds the maximum allowed limit. Try reducing the number of pages per request, using simpler page content, or splitting into multiple smaller operations."
}
JSON

Try it out

This uses your live Canva data.

This is not a sandbox/playground. This form performs API requests against your account's actual live Canva data. Make sure that you understand what the request is doing, as well as the requirements for each parameter detailed above.

Step 1: Enter your access token

To get started, generate an access token or provide your own below