> ## 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 image transformation 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 apply one or more transformations to an image asset. A successful job produces a single new image asset with all of the requested transformations applied. The source asset isn't modified, and intermediate results aren't returned. The request requires the ID of the source asset and at least one transformation. The source asset must be an image asset, such as one created using the [Asset upload APIs](https://www.canva.dev/docs/apps/rest-apis/reference/assets/). Transformations are applied in the order provided, with each one stacked on the result of the previous one. Starting a job consumes the user's [AI credit allowance](https://www.canva.com/help/ai-access/). If the user has reached their AI allowance limit, the request returns a `402` error with the `credit_quota_exceeded` code. Polling for the result of a job using the [Get image transformation job API](https://www.canva.dev/docs/apps/rest-apis/reference/image-transformations/get-image-transformation-job/) doesn't consume any of the allowance. 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 image transformation jobs created with this API using the [Get image transformation job API](https://www.canva.dev/docs/apps/rest-apis/reference/image-transformations/get-image-transformation-job/). ## HTTP method and URL path POST https\://api.canva.com/rest/v1/image-transformations ### Rate limit This operation is rate limited to 20 requests per minute for each user of your app. ## Authentication and authorization This endpoint supports public or private apps, and requires a valid OAuth access token that acts on behalf of a user (OAuth authorization code flow). 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): * `asset:read` * `asset:write` ## 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 The ID of the source asset to transform. The asset must be an image asset; referencing any other asset type (such as a video) fails with an `unsupported_content_type` error. The asset must also have finished uploading. An asset that is still uploading has no image to transform yet and fails with an `asset_not_ready` error. If you've just created the asset, poll its upload job — for example with the [Get asset upload job](https://www.canva.dev/docs/apps/rest-apis/reference/assets/get-asset-upload-job/) endpoint — until it returns a `success` status before starting a transformation. The transformations to apply, in order. Must contain at least one transformation. Each transformation is stacked on the result of the previous one. The job's result is a single new image asset with all of the transformations applied; intermediate results are not returned. **Minimum items:** `1` **Maximum items:** `20` Removes the background from an image, keeping the foreground subject. The resulting image has a transparent background. This transformation takes no parameters. The output image is limited to a maximum of 25 megapixels. If the source image is larger, the output image is scaled down to stay within this limit. Requires the user to have the `background_removal` capability. To check this before creating a job, use the [Get user capabilities API](https://www.canva.dev/docs/apps/rest-apis/reference/users/get-user-capabilities/). The type of transformation to apply. Currently, the only supported value is `background_removal`. **Available values:** The only valid value is `background_removal`. A name for the new image asset that the job produces. Canva doesn't localize this value, so provide a name in the user's language. When omitted, the new asset inherits the name of the source asset. **Minimum length:** `1` **Maximum length:** `255` ## Example request Examples for using the `/v1/image-transformations` endpoint: ```sh curl --request POST 'https://api.canva.com/rest/v1/image-transformations' \ --header 'Authorization: Bearer {token}' \ --header 'Content-Type: application/json' \ --data '{ "asset_id": "Msd59349ff", "name": "My Awesome Upload with the background removed", "transformations": [ { "type": "background_removal" } ] }' ``` ```js const fetch = require("node-fetch"); fetch("https://api.canva.com/rest/v1/image-transformations", { method: "POST", headers: { "Authorization": "Bearer {token}", "Content-Type": "application/json", }, body: JSON.stringify({ "asset_id": "Msd59349ff", "name": "My Awesome Upload with the background removed", "transformations": [ { "type": "background_removal" } ] }), }) .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/image-transformations")) .header("Authorization", "Bearer {token}") .header("Content-Type", "application/json") .method("POST", HttpRequest.BodyPublishers.ofString("{\"asset_id\": \"Msd59349ff\", \"name\": \"My Awesome Upload with the background removed\", \"transformations\": [{\"type\": \"background_removal\"}]}")) .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 = { "asset_id": "Msd59349ff", "name": "My Awesome Upload with the background removed", "transformations": [ { "type": "background_removal" } ] } response = requests.post("https://api.canva.com/rest/v1/image-transformations", 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/image-transformations"), Headers = { { "Authorization", "Bearer {token}" }, }, Content = new StringContent( "{\"asset_id\": \"Msd59349ff\", \"name\": \"My Awesome Upload with the background removed\", \"transformations\": [{\"type\": \"background_removal\"}]}", 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(`{ "asset_id": "Msd59349ff", "name": "My Awesome Upload with the background removed", "transformations": [ { "type": "background_removal" } ] }`) url := "https://api.canva.com/rest/v1/image-transformations" 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/image-transformations", CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => array( 'Authorization: Bearer {token}', 'Content-Type: application/json', ), CURLOPT_POSTFIELDS => json_encode([ "asset_id" => "Msd59349ff", "name" => "My Awesome Upload with the background removed", "transformations" => [ [ "type" => "background_removal" ] ] ]) )); $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/image-transformations') 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: Details about the image transformation job. If the job status is `success`, the job's `result` is present. Properties of job} defaultExpanded={true}> The status of the image transformation job. A newly created job will be `in_progress` and will eventually become `success` or `failed`. A job may also complete immediately, returning `success` or `failed` from job creation. If the status is `success`, the job's `result` is present. **Available values:** * `failed` * `in_progress` * `success` The image transformation job ID. Only present if the job status is `in_progress`. A job that completes immediately returns its `result` or `error` directly and has no ID to poll. Result of the image transformation job. Only present if the job status is `success`. Properties of result}> The new image asset produced by applying all of the requested transformations. Properties of asset}> Type of an asset. **Available values:** * `image` * `video` The ID of the asset. The name of the asset. The user-facing tags attached to the asset. Users can add these tags to their uploaded assets, and they can search their uploaded assets in the Canva UI by searching for these tags. For information on how users use tags, see the [Canva Help Center page on asset tags](https://www.canva.com/help/add-edit-tags/). When the asset was added to Canva, as a Unix timestamp (in seconds since the Unix Epoch). When the asset was last updated in Canva, as a Unix timestamp (in seconds since the Unix Epoch). Metadata for the user, consisting of the User ID and Team ID. Properties of owner}> The ID of the user. The ID of the user's Canva Team. 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. Type-specific metadata for the asset. **Available values:** The only valid value is `image`. The width of the image in pixels. The height of the image in pixels. AI-generated tags for the image. **Available values:** The only valid value is `video`. The width of the video in pixels. The height of the video in pixels. The duration of the video in seconds. The import status of the asset. Properties of import_status}> State of the import job for an uploaded asset. **Available values:** * `failed` * `in_progress` * `success` If the import fails, this object provides details about the error. Properties of error}> A human-readable description of what went wrong. A short string indicating why the upload failed. This field can be used to handle errors programmatically. **Available values:** * `file_too_big` * `import_failed` If the image transformation job fails, this object provides details about the error. Only present if the job status is `failed`. Properties of error}> Error code indicating what went wrong with the image transformation. **Available values:** * `no_foreground_found`: No foreground subject was found in the image, so there is no background to remove. * `quota_exceeded`: The user has run out of quota, such as their AI credit quota. The quota isn't necessarily specific to the requested transformations. * `internal_error`: An unexpected error occurred during the transformation. A human-readable description of what went wrong. ## Example responses ### In progress job ```json { "job": { "id": "450a76e7-f96f-43ae-9c37-0e1ce492ac72", "status": "in_progress" } } ``` ### Successfully completed job ```json { "job": { "status": "success", "result": { "asset": { "id": "Msd59349ff", "type": "image", "name": "My Awesome Upload with the background removed", "tags": [ "image", "holiday", "best day ever" ], "owner": { "user_id": "oU123456AbCdE", "team_id": "oB123456AbCdE" }, "created_at": 1377396000, "updated_at": 1692928800, "thumbnail": { "width": 595, "height": 335, "url": "https://document-export.canva.com/Vczz9/zF9vzVtdADc/2/thumbnail/0001.png?" } } } } } ``` ### Failed job ```json { "job": { "status": "failed", "error": { "code": "no_foreground_found", "message": "No foreground subject was found in the image, so there is no background to remove." } } } ``` ## 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 ##### The request field does not match expected format ```json { "code": "invalid_request", "message": "{fieldValue} does not match expected format for {fieldName}" } ``` ##### The asset is not an image asset ```json { "code": "unsupported_content_type", "message": "Asset is not an image asset: {assetId}" } ``` ##### The asset is still being uploaded, so it can't be transformed yet ```json { "code": "asset_not_ready", "message": "Asset is still being uploaded and has no image to transform yet: {assetId}" } ``` ### 401 Unauthorized 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 ##### The OAuth client credentials are invalid ```json { "code": "invalid_client", "message": "Client {clientId} not available" } ``` ##### Access token could not be decoded or signature could not be verified. ```json { "code": "invalid_access_token", "message": "Access token is invalid" } ``` ##### Client credentials or body auth are missing from the request ```json { "code": "invalid_client", "message": "Client credentials or body auth are missing from the request." } ``` ##### Authorization header has wrong number of components ```json { "code": "invalid_access_token", "message": "Malformed Authorization header: wrong number of components" } ``` ##### Authorization header has invalid mode ```json { "code": "invalid_access_token", "message": "Malformed Authorization header: invalid mode" } ``` ##### Token couldn't be introspected ```json { "code": "invalid_access_token", "message": "Token couldn't be introspected" } ``` ##### Access token is revoked ```json { "code": "revoked_access_token", "message": "Access token is revoked" } ``` ##### Missing Authorization header ```json { "code": "invalid_access_token", "message": "Missing Authorization header" } ``` ##### Malformed Authorization header ```json { "code": "invalid_access_token", "message": "Malformed Authorization header" } ``` ### 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 response ##### Image transformation is not enabled for this client ```json { "code": "permission_denied", "message": "Image transformation is not enabled" } ``` ### 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 ##### The asset was not found ```json { "code": "asset_not_found", "message": "Asset not found" } ```