> ## Documentation Index
> Fetch the complete documentation index at: https://www.canva.dev/docs/apps/llms.txt
> Use this file to discover all available pages before exploring further.
# 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](https://www.canva.dev/docs/apps/rest-apis/versions/).
* Public apps 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](https://www.canva.dev/docs/apps/rest-apis/requests-responses/#asynchronous-job-endpoints) 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.
At this stage, only a single operation per request is supported by default, and passing multiple operations will fail. Contact Canva to enable multi-operation mode for your app.
For more information on the workflow for using asynchronous jobs, see [API requests and responses](https://www.canva.dev/docs/apps/rest-apis/requests-responses/#asynchronous-job-endpoints). You can check the status and get the results of jobs created with this API using the [Get design merge job API](https://www.canva.dev/docs/apps/rest-apis/reference/merges/get-design-merge-job/).
## 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 app.
## Authentication and authorization
This endpoint requires a valid access token that acts on behalf of a user. For more information, see [Generate an access token](/docs/apps/rest-apis/reference/authentication/generate-access-token).
### Scopes
The access token must have all the following [scopes](/docs/apps/rest-apis/scopes) (permissions):
* `design:content:write`
* `design:meta:read`
## Header parameters
Provides credentials to authenticate the request, in the form of a `Bearer` token.
For example: `Authorization: Bearer {token}`
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.
The type of merge job to create.
**Available values:** The only valid value is `create_new_design`.
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.
The type of merge operation.
**Available values:** The only valid value is `insert_pages`.
A design source from which pages are inserted.
The type of source to insert pages from.
**Available values:** The only valid value is `design`.
The ID of the source design.
One-based page numbers to insert from the source design. If omitted, all pages from the design are inserted.
**Minimum items:** `1`
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.
The type of merge operation.
**Available values:** The only valid value is `move_pages`.
One-based number of the pages to move (evaluated at the time this operation runs). Pages are moved in order.
**Minimum items:** `1`
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.
The type of merge operation.
**Available values:** The only valid value is `delete_pages`.
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`
Title for the new design.
**Minimum length:** `1`
**Maximum length:** `255`
Modifies an existing design by inserting, moving, or deleting pages.
The type of merge job to create.
**Available values:** The only valid value is `modify_existing_design`.
The ID of the design to modify.
Supports insert, move, and delete operations.
**Minimum items:** `1`
**Maximum items:** `500`
Inserts pages from a source design into the target design.
The type of merge operation.
**Available values:** The only valid value is `insert_pages`.
A design source from which pages are inserted.
The type of source to insert pages from.
**Available values:** The only valid value is `design`.
The ID of the source design.
One-based page numbers to insert from the source design. If omitted, all pages from the design are inserted.
**Minimum items:** `1`
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.
The type of merge operation.
**Available values:** The only valid value is `move_pages`.
One-based number of the pages to move (evaluated at the time this operation runs). Pages are moved in order.
**Minimum items:** `1`
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.
The type of merge operation.
**Available values:** The only valid value is `delete_pages`.
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`
Optional new title for the design.
**Minimum length:** `1`
**Maximum length:** `255`
## Example request
Examples for using the `/v1/merges` endpoint:
```sh
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"
}'
```
```js
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));
```
```java
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 response = HttpClient.newHttpClient().send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.body());
}
}
```
```py
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())
```
```csharp
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);
};
```
```go
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))
}
```
```php
$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;
}
```
```ruby
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 = <
## Success response
If successful, the endpoint returns a `200` response with a JSON body with the following parameters:
The details of a design merge job.
Properties of job>} defaultExpanded={true}>
The ID of the design merge job.
**Available values:**
* `in_progress`: The merge job is still running.
* `success`: The merge job completed successfully.
* `failed`: The merge job failed.
Properties of result>}>
Basic details about the design, such as the design's ID, title, and URL.
Properties of design>}>
The design ID.
A temporary set of URLs for viewing or editing the design.
Properties of urls>}>
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](https://www.canva.dev/docs/apps/rest-apis/return-navigation-guide/) workflows.
NOTE: This is not a permanent URL, it is only valid for 30 days.
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](https://www.canva.dev/docs/apps/rest-apis/return-navigation-guide/) workflows.
NOTE: This is not a permanent URL, it is only valid for 30 days.
When the design was created in Canva, as a Unix timestamp (in seconds since the Unix
Epoch).
When the design was last updated in Canva, as a Unix timestamp (in seconds since the
Unix Epoch).
The design title.
URL of the design.
A thumbnail image representing the object.
Properties of thumbnail>}>
The width of the thumbnail image in pixels.
The height of the thumbnail image in pixels.
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.
The total number of pages in the design. Some design types don't have pages (for example, Canva docs).
If the merge job fails, this object provides details about the error.
Properties of error>}>
**Available values:**
* `thumbnail_generation_error`
* `merge_error`
* `create_design_error`
* `modify_design_error`
A human-readable description of what went wrong.
## Example response
```json
{
"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?"
},
"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."
}
}
}
```
## Error responses
### 400 Bad Request
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](/docs/apps/rest-apis/error-responses/).
A human-readable description of what went wrong.
#### Example error responses
##### Invalid merge job type
```json
{
"code": "invalid_request",
"message": "Invalid merge job type: {jobType}"
}
```
##### Invalid operation
```json
{
"code": "bad_request_params",
"message": "Invalid operation: {message}"
}
```
##### Invalid page number
```json
{
"code": "bad_request_params",
"message": "Page number {pageNumber} is out of range (design has {totalPages} pages)"
}
```
##### Unsupported page type
```json
{
"code": "bad_request_params",
"message": "Source design '{designId}' has unsupported page type: {pageType}. Only fixed pages are supported."
}
```
##### Unsupported document type
```json
{
"code": "bad_request_params",
"message": "Design '{designId}' has unsupported document type: {documentType}."
}
```
##### Operation not supported
```json
{
"code": "bad_request_params",
"message": "{message}"
}
```
### 402 Payment Required
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](/docs/apps/rest-apis/error-responses/).
A human-readable description of what went wrong.
#### Example error responses
##### User has reached their credit quota limit
```json
{
"code": "credit_quota_exceeded",
"message": "User has exceeded their credit quota"
}
```
##### App has reached its credit quota limit
```json
{
"code": "app_credit_quota_exceeded",
"message": "App has exceeded its credit quota"
}
```
### 403 Forbidden
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](/docs/apps/rest-apis/error-responses/).
A human-readable description of what went wrong.
#### Example error responses
##### Not allowed to access design
```json
{
"code": "permission_denied",
"message": "Not allowed to access design '{designId}'"
}
```
##### Unauthorized access to private resource
```json
{
"code": "permission_denied",
"message": "Source design contains private resources that you don't have access to."
}
```
### 404 Not Found
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](/docs/apps/rest-apis/error-responses/).
A human-readable description of what went wrong.
#### Example error response
##### Design not found for merge operation
```json
{
"code": "not_found",
"message": "Design '{designId}' not found"
}
```
### 413 Request Entity Too Large
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](/docs/apps/rest-apis/error-responses/).
A human-readable description of what went wrong.
#### Example error response
##### Request too large
```json
{
"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."
}
```