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
https://api.canva.com /rest /v1 /mergesThis 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:writedesign:meta:read
Header parameters
Content-TypestringIndicates 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.
typestringThe type of merge job to create.
Available values: The only valid value is create_new_design.
operationsDesignMergeOperation[]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.
typestringThe type of merge operation.
Available values: The only valid value is insert_pages.
sourceMergeSourceForInsertPagesOperationA design source from which pages are inserted.
typestringThe type of source to insert pages from.
Available values: The only valid value is design.
design_idstringThe ID of the source design.
page_numbersinteger[]One-based page numbers to insert from the source design. If omitted, all pages from the design are inserted.
Minimum items: 1
after_page_numberintegerInsert 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.
typestringThe type of merge operation.
Available values: The only valid value is move_pages.
from_page_numbersinteger[]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_numberintegerDestination position: insert the moved pages after this one-based page number. Use 0 to move to the beginning.
Deletes pages from the target design.
typestringThe type of merge operation.
Available values: The only valid value is delete_pages.
page_numbersinteger[]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
titlestringTitle for the new design.
Minimum length: 1
Maximum length: 255
Modifies an existing design by inserting, moving, or deleting pages.
typestringThe type of merge job to create.
Available values: The only valid value is modify_existing_design.
design_idstringThe ID of the design to modify.
operationsDesignMergeOperation[]Supports insert, move, and delete operations.
Minimum items: 1
Maximum items: 500
Inserts pages from a source design into the target design.
typestringThe type of merge operation.
Available values: The only valid value is insert_pages.
sourceMergeSourceForInsertPagesOperationA design source from which pages are inserted.
typestringThe type of source to insert pages from.
Available values: The only valid value is design.
design_idstringThe ID of the source design.
page_numbersinteger[]One-based page numbers to insert from the source design. If omitted, all pages from the design are inserted.
Minimum items: 1
after_page_numberintegerInsert 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.
typestringThe type of merge operation.
Available values: The only valid value is move_pages.
from_page_numbersinteger[]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_numberintegerDestination position: insert the moved pages after this one-based page number. Use 0 to move to the beginning.
Deletes pages from the target design.
typestringThe type of merge operation.
Available values: The only valid value is delete_pages.
page_numbersinteger[]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
titlestringOptional 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"}'
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));
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());}}
import requestsheaders = {"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())
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);};
package mainimport ("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))}
$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;}
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 = truerequest = 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_BODYresponse = http.request(request)puts response.read_body
Success response
If successful, the endpoint returns a 200 response with a JSON body with the following parameters:
jobDesignMergeJobThe details of a design merge job.
idstringThe ID of the design merge job.
statusstringAvailable values:
in_progress: The merge job is still running.success: The merge job completed successfully.failed: The merge job failed.
resultDesignMergeJobResultdesignDesignSummaryBasic details about the design, such as the design's ID, title, and URL.
idstringThe design ID.
urlsDesignLinksA temporary set of URLs for viewing or editing the design.
edit_urlstringA 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_urlstringA 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_atintegerWhen the design was created in Canva, as a Unix timestamp (in seconds since the Unix Epoch).
updated_atintegerWhen the design was last updated in Canva, as a Unix timestamp (in seconds since the Unix Epoch).
titlestringThe design title.
urlstringURL of the design.
thumbnailThumbnailA thumbnail image representing the object.
widthintegerThe width of the thumbnail image in pixels.
heightintegerThe height of the thumbnail image in pixels.
urlstringA 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_countintegerThe total number of pages in the design. Some design types don't have pages (for example, Canva docs).
errorDesignMergeErrorIf the merge job fails, this object provides details about the error.
codestringAvailable values:
thumbnail_generation_errormerge_errorcreate_design_errormodify_design_error
messagestringA 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."}}}
Error responses
400 Bad Request
codestringA short string indicating what failed. This field can be used to handle errors programmatically. For a complete list of error codes, see Error responses.
messagestringA human-readable description of what went wrong.
Example error response
{"code": "invalid_request","message": "Invalid merge job type: {jobType}"}
403 Forbidden
codestringA short string indicating what failed. This field can be used to handle errors programmatically. For a complete list of error codes, see Error responses.
messagestringA human-readable description of what went wrong.
Example error response
{"code": "permission_denied","message": "Not allowed to access design '{designId}'"}
404 Not Found
codestringA short string indicating what failed. This field can be used to handle errors programmatically. For a complete list of error codes, see Error responses.
messagestringA human-readable description of what went wrong.
Example error response
{"code": "not_found","message": "Design '{designId}' not found"}
413 Request Entity Too Large
codestringA short string indicating what failed. This field can be used to handle errors programmatically. For a complete list of error codes, see Error responses.
messagestringA 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."}