> ## 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. # upload API reference for the upload method. Uploads an asset to the user's private media library. ## Usage ### Upload an image from a URL ```typescript import { type ImageRef, upload } from "@canva/asset"; // If you are uploading an image that is derived from another image, pass its imageRef, otherwise set it as undefined const parentRef = "PLACEHOLDER_IMAGE_REF" as ImageRef; await upload({ type: "image", parentRef, url: "https://example.com/image.jpg", mimeType: "image/jpeg", thumbnailUrl: "https://example.com/thumb.jpg", // If you used AI to edit the image, set this to "app_generated" otherwise set it to "none" aiDisclosure: "none" }); ``` ### Upload an image from a data URL ```typescript import { type ImageRef, upload } from "@canva/asset"; // If you are uploading an image that is derived from another image, pass its imageRef, otherwise set it as undefined const parentRef = "PLACEHOLDER_IMAGE_REF" as ImageRef; await upload({ type: "image", parentRef, url: "data:image/jpeg;base64,/9j/4AAQSkZJRg...", mimeType: "image/jpeg", thumbnailUrl: "data:image/jpeg;base64,/9j/4AAQSkZJRg...", // If you used AI to edit the image, set this to "app_generated" otherwise set it to "none" aiDisclosure: "none" }); ``` ### Upload a video from a URL ```typescript import { type VideoRef, upload } from "@canva/asset"; // If you are uploading a video that is derived from another video, pass its videoRef, otherwise set it as undefined const parentRef = "PLACEHOLDER_VIDEO_REF" as VideoRef; await upload({ type: "video", parentRef, url: "https://example.com/video.mp4", mimeType: "video/mp4", thumbnailImageUrl: "https://example.com/thumb.jpg", // If you used AI to edit the video, set this to "app_generated" otherwise set it to "none" aiDisclosure: "none" }); ``` ### Upload an audio file from a URL ```typescript import { upload } from "@canva/asset"; await upload({ type: "audio", url: "https://example.com/audio.mp3", mimeType: "audio/mp3", title: "My Audio", durationMs: 30000, aiDisclosure: "none" }); ``` ### Upload a Lottie animation from a URL ```typescript import { type VideoRef, upload } from "@canva/asset"; // If you are uploading a video that is derived from another video, pass its videoRef, otherwise set it as undefined const parentRef = "PLACEHOLDER_VIDEO_REF" as VideoRef; await upload({ type: "video", parentRef, url: "https://example.com/animation.json", mimeType: "application/json", thumbnailImageUrl: "https://example.com/thumb.jpg", // If you used AI to edit the video, set this to "app_generated" otherwise set it to "none" aiDisclosure: "none" }); ``` ### Upload an asset with dimensions (image and video only) ```typescript import { type ImageRef, upload } from "@canva/asset"; // If you are uploading an image that is derived from another image, pass its imageRef, otherwise set it as undefined const parentRef = "PLACEHOLDER_IMAGE_REF" as ImageRef; await upload({ type: "image", parentRef, url: "https://example.com/image.jpg", mimeType: "image/jpeg", thumbnailUrl: "https://example.com/thumb.jpg", // If you used AI to edit the image, set this to "app_generated" otherwise set it to "none" aiDisclosure: "none", width: 1920, height: 1080 }); ``` ### Upload an AI-generated asset ```typescript import { upload } from "@canva/asset"; await upload({ type: "image", url: "https://example.com/ai-image.jpg", mimeType: "image/jpeg", thumbnailUrl: "https://example.com/thumb.jpg", aiDisclosure: "app_generated" }); ``` ### Upload an image with a custom name ```typescript import { type ImageRef, upload } from "@canva/asset"; // If you are uploading an image that is derived from another image, pass its imageRef, otherwise set it as undefined const parentRef = "PLACEHOLDER_IMAGE_REF" as ImageRef; await upload({ type: "image", parentRef, name: "My Vacation Photo", url: "https://example.com/image.jpg", mimeType: "image/jpeg", thumbnailUrl: "https://example.com/thumb.jpg", // If you used AI to edit the image, set this to "app_generated" otherwise set it to "none" aiDisclosure: "none" }); ``` ### Upload a video with a custom name ```typescript import { type VideoRef, upload } from "@canva/asset"; // If you are uploading a video that is derived from another video, pass its videoRef, otherwise set it as undefined const parentRef = "PLACEHOLDER_VIDEO_REF" as VideoRef; await upload({ type: "video", parentRef, name: "Product Demo", url: "https://example.com/video.mp4", mimeType: "video/mp4", thumbnailImageUrl: "https://example.com/thumb.jpg", // If you used AI to edit the video, set this to "app_generated" otherwise set it to "none" aiDisclosure: "none" }); ``` ### Upload a derived image with parentRef ```typescript import { type ImageRef, getTemporaryUrl, upload } from "@canva/asset"; import { useSelection } from "@canva/app-hooks"; const selectedContent = useSelection("image"); const draft = await selectedContent.read(); for (const content of draft.contents) { // Fetch a temporary URL to the original image const { url } = await getTemporaryUrl({ type: "image", ref: content.ref }); // Apply any edits you want to the image const processedImageUrl = await applyImageEffect(url); // Upload the edited image const asset = await upload({ type: "image", parentRef: content.ref, url: processedImageUrl, mimeType: "image/jpeg", thumbnailUrl: processedImageUrl, // If you used AI to edit the image, set this to "app_generated" otherwise set it to "none" aiDisclosure: "app_generated" }); // Replace the image ref with the new image ref content.ref = asset.ref; } // Update the image with the edited image await draft.save(); ``` ### Upload a derived video with parentRef ```typescript import { type VideoRef, getTemporaryUrl, upload } from "@canva/asset"; // If you are uploading a video that is derived from another video, pass its videoRef, otherwise set it as undefined const originalVideoRef = "PLACEHOLDER_VIDEO_REF" as VideoRef; const { url } = await getTemporaryUrl({ type: "video", ref: originalVideoRef }); const processedVideoUrl = await processVideo(url); await upload({ type: "video", parentRef: originalVideoRef, url: processedVideoUrl, mimeType: "video/mp4", thumbnailImageUrl: "https://example.com/processed-thumb.jpg", // If you used AI to edit the video, set this to "app_generated" otherwise set it to "none" aiDisclosure: "none" }); ``` ### Wait for an asset to finish uploading ```typescript import { type VideoRef, upload } from "@canva/asset"; // If you are uploading a video that is derived from another video, pass its videoRef, otherwise set it as undefined const parentRef = "PLACEHOLDER_VIDEO_REF" as VideoRef; // Start uploading the asset const asset = await upload({ type: "video", parentRef, url: "https://example.com/video.mp4", mimeType: "video/mp4", thumbnailImageUrl: "https://example.com/thumb.jpg", // If you used AI to edit the video, set this to "app_generated" otherwise set it to "none" aiDisclosure: "none" }); // Wait for the upload to complete await asset.whenUploaded(); ``` ## Parameters Options for uploading an asset to the user's private media library. Options for uploading an image asset to the user's private media library. The type of asset. The only valid value is `"image"`. The URL of the image file to upload. This can be an external URL or a data URL. Requirements for external URLs: * Must use HTTPS * Must return a `200` status code * `Content-Type` must match the file's MIME type * Must be publicly accessible (i.e. not a localhost URL) * Must not redirect * Must not contain an IP address * Maximum length: 4096 characters * Must not contain whitespace * Must not contain these characters: `>`, `<`, `{`, `}`, `^`, backticks * Maximum file size: 50MB Requirements for data URLs: * Must include `;base64` for base64-encoded data * Maximum size: 10MB (10 × 1024 × 1024 characters) Requirements for SVGs: * Disallowed elements: * `a` * `altglyph` * `altglyphdef` * `altglyphitem` * `animate` * `animatemotion` * `animatetransform` * `cursor` * `discard` * `font` * `font-face` * `font-face-format` * `font-face-name` * `font-face-src` * `font-face-uri` * `foreignobject` * `glyph` * `glyphref` * `missing-glyph` * `mpath` * `script` * `set` * `switch` * `tref` * Disallowed attributes: * `crossorigin` * `lang` * `media` * `onload` * `ping` * `referrerpolicy` * `rel` * `rendering-intent` * `requiredextensions` * `requiredfeatures` * `systemlanguage` * `tabindex` * `transform-origin` * `unicode` * `vector-effect` * The `href` attribute of an `image` element only supports data URLs for PNG and JPEG images. * The URL in the `href` attribute must not point to a location outside of the SVG. * The `style` attribute must not use the `mix-blend-mode` property. The MIME type of the image file. **Available values**: * `"image/jpeg"` * `"image/heic"` * `"image/png"` * `"image/svg+xml"` * `"image/webp"` * `"image/tiff"` The URL of a thumbnail image to display while the image is queued for upload. This can be an external URL or a data URL. Requirements for external URLs: * Must use HTTPS * Must support [Cross-Origin Resource Sharing](https://www.canva.dev/docs/apps/cross-origin-resource-sharing/) * Must be a PNG, JPEG, or SVG file * Maximum length: 4096 characters Requirements for data URLs: * Must include `;base64` for base64-encoded data * Maximum size: 10MB (10 × 1024 × 1024 characters) A disclosure identifying if the app generated this image using AI Helps users make informed decisions about the content they interact with. See AiDisclosure for the full definition. **App Generated** 'app\_generated' indicates when the app creates or significantly alters an asset using AI. Includes when the app requests a third-party service to take similar action on an image using AI. Required for the following cases (this list is not exhaustive): | Case | Reason | | --------------------------------------------------------------- | ------------------------------------ | | AI generates a new image from scratch | Creates new creative content | | AI changes the style of the image e.g. makes it cartoon | Significantly alters the style | | AI removes an object and replaces it with new content | Creates new creative content | | AI changes the facial expression of a person in an image | Can alter content's original meaning | | AI composites multiple images together | Significantly alters context | | AI expands an image by generating new content to fill the edges | Creates new creative content | | AI replaces background by generating new content | Creates new creative content | **None** 'none' indicates when the app doesn't create or significantly alter an asset using AI, or as a part of a request to third-party hosted content. Required for the following cases (this list is not exhaustive): | Case | Reason | | -------------------------------------------------- | ----------------------------------------- | | Asset comes from an asset library | Didn't generate the asset itself | | AI corrects red eyes | A minor correction | | AI removes background without replacement | Doesn't change original meaning by itself | | AI changes the color of an object in an image | Doesn't change original meaning by itself | | AI detects image defects and suggests manual fixes | Didn't change the asset itself | | AI adjusts brightness and contrast on an image | Doesn't change original meaning by itself | | AI upscales an image | Doesn't change original meaning by itself | **Available values**: * `"app_generated"` * `"none"` A human-readable name for the image asset. This name is displayed in the user's media library and helps users identify and find the asset later. If not provided, Canva will generate a name based on the asset's URL or a unique identifier. Requirements: * Minimum length: 1 character (empty strings are not allowed) * Maximum length: 255 characters The ref of the original asset from which this new asset was derived. For example, if an app applies an effect to an image, `parentRef` should contain the ref of the original image. A width, in pixels. A height, in pixels. Options for uploading a video asset to the user's private media library. The type of asset. The only valid value is `"video"`. The URL of the video file to upload. Requirements: * Must use HTTPS * Must return a `200` status code * `Content-Type` must match the file's MIME type * Must be publicly accessible (i.e. not a localhost URL) * Must not redirect * Must not contain an IP address * Maximum length: 4096 characters * Must not contain whitespace * Must not contain these characters: `>`, `<`, `{`, `}`, `^`, backticks * Maximum file size: 1000MB (1GB) The MIME type of the video file. **Available values**: * `"video/avi"` * `"video/x-msvideo"` * `"image/gif"` * `"video/x-m4v"` * `"video/x-matroska"` * `"video/quicktime"` * `"video/mp4"` * `"video/mpeg"` * `"video/webm"` * `"application/json"` The URL of a thumbnail image to use as a fallback if `thumbnailVideoUrl` isn't provided. This can be an external URL or a data URL. Requirements for external URLs: * Must use HTTPS * Must support [Cross-Origin Resource Sharing](https://www.canva.dev/docs/apps/cross-origin-resource-sharing/) * Must be a PNG, JPEG, or SVG file * Maximum length: 4096 characters Requirements for data URLs: * Must include `;base64` for base64-encoded data * Maximum size: 10MB (10 × 1024 × 1024 characters) * The dimensions of the thumbnail must match the video's aspect ratio to prevent the thumbnail from appearing squashed or stretched A disclosure identifying if the app generated this video using AI. Helps users make informed decisions about the content they interact with. See AiDisclosure for the full definition. **App Generated** 'app\_generated' indicates when the app creates or significantly alters an asset using AI. Includes when the app requests a third-party service to take similar action on a video using AI. Required for the following cases (this list is not exhaustive): | Case | Reason | | -------------------------------------------------------------- | ------------------------------ | | AI generates a new video from scratch | Creates new creative content | | AI changes the style of the video e.g. makes it cartoon | Significantly alters the style | | AI adds subtitles that rely on subjective interpretation | Creates new creative content | | AI expands a video by generating new content to fill the edges | Creates new creative content | | AI animates an image | Creates new creative content | | AI fixes defects e.g. blur in a video by generating details | Creates new creative content | | AI generates a talking head presenter | Creates new creative content | **None** 'none' indicates when the app doesn't create or significantly alter an asset using AI, or as a part of a request to third-party hosted content. Required for the following cases (this list is not exhaustive): | Case | Reason | | -------------------------------------------------------- | ----------------------------------------- | | Asset comes from an asset library | Didn't generate the asset itself | | AI corrects red eyes | A minor correction | | AI adjusts brightness and contrast on a video | Doesn't change original meaning by itself | | AI creates a slow motion effect in a video | Doesn't change original meaning by itself | | AI adds AI word-by-word transcribed subtitles to a video | Doesn't change original meaning by itself | **Available values**: * `"app_generated"` * `"none"` A human-readable name for the video asset. This name is displayed in the user's media library and helps users identify and find the asset later. If not provided, Canva will generate a name based on the asset's URL or a unique identifier. Requirements: * Minimum length: 1 character (empty strings are not allowed) * Maximum length: 255 characters The ref of the original asset from which this new asset was derived. For example, if an app applies an effect to a video, `parentRef` should contain the ref of the original video. The URL of a thumbnail video to display while the video is queued for upload. Requirements: * Must use HTTPS * Must support [Cross-Origin Resource Sharing](https://www.canva.dev/docs/apps/cross-origin-resource-sharing/) * Maximum length: 4096 characters * The dimensions of the thumbnail video must match the video's aspect ratio to prevent the thumbnail from appearing squashed or stretched * Must not be an AVI file. Although our APIs support uploading AVI videos, Canva can't preview them because of native support of browsers A width, in pixels. A height, in pixels. Options for uploading an audio asset to the user's private media library. The type of asset. The only valid value is `"audio"`. The URL of the audio file to upload to the user's private media library. Requirements: * Must use HTTPS * Must return a `200` status code * `Content-Type` must match the file's MIME type * Must be publicly accessible (i.e. not a localhost URL) * Must not redirect * Must not contain an IP address * Maximum length: 4096 characters * Must not contain whitespace * Must not contain these characters: `>`, `<`, `{`, `}`, `^`, backticks * Maximum file size: 250MB The MIME type of the audio file. **Available values**: * `"audio/mpeg"` * `"audio/mp4"` * `"audio/x-m4a"` * `"audio/mp3"` * `"audio/ogg"` * `"audio/wav"` * `"audio/x-wav"` * `"audio/wave"` * `"audio/vnd.wave"` * `"audio/x-pn-wav"` * `"audio/webm"` A human-readable title for the audio asset. This title is displayed in the Canva editor. The initial playback duration of the audio file, in milliseconds. A disclosure identifying if the app generated this audio using AI. Helps users make informed decisions about the content they interact with. See AiDisclosure for the full definition. **App Generated** 'app\_generated' indicates when the app creates or significantly alters an asset using AI. Includes when the app requests a third-party service to take similar action on an audio asset using AI. Required for the following cases (this list is not exhaustive): | Case | Reason | | --------------------------------------------------- | ---------------------------- | | AI generates a music track from scratch | Creates new creative content | | AI generates sounds from scratch e.g. animal sounds | Creates new creative content | | AI converts text to speech | Creates new creative content | | AI changes the mood or genre of audio/music | Significantly alters context | | AI adjusts pitch or tempo for a creative purpose | Significantly alters context | **None** 'none' indicates when the app doesn't create or significantly alter an asset using AI, or as a part of a request to third-party hosted content. Required for the following cases (this list is not exhaustive): | Case | Reason | | --------------------------------- | -------------------------------- | | Asset comes from an asset library | Didn't generate the asset itself | | AI balances audio across speakers | A minor correction | **Available values**: * `"app_generated"` * `"none"` ## Returns An asset that's queued for upload to the user's private media library. This is a `Promise` that resolves with the following object: An image asset that's queued for upload to the user's private media library. A unique identifier that points to an image asset in Canva's backend. Returns a `Promise` that resolves when the asset has finished uploading. **Returns** `Promise` A video asset that's queued for upload to the user's private media library. A unique identifier that points to a video asset in Canva's backend. Returns a `Promise` that resolves when the asset has finished uploading. **Returns** `Promise` An audio asset that's queued for upload to the user's private media library. A unique identifier that points to the audio asset in Canva's backend. Returns a `Promise` that resolves when the asset has finished uploading. **Returns** `Promise` ## Permissions To use this method, the `canva:asset:private:write` permission must be enabled for the app. To learn more, see [Permissions](https://www.canva.dev/docs/apps/configuring-intents-permissions/). ## Rate limit This method has a rate limit of 120 requests every minute.