home / skills / vm0-ai / vm0-skills / canva

canva skill

/canva

This skill enables you to manage Canva designs, folders, assets, and comments via curl, streamlining creation, export, and collaboration.

npx playbooks add skill vm0-ai/vm0-skills --skill canva

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
9.5 KB
---
name: canva
description: Canva design platform API via curl. Use this skill to list, create, and export designs, manage folders, upload assets, and add comments.
vm0_secrets:
  - CANVA_TOKEN
---

# Canva API

Use the Canva Connect API via direct `curl` calls to manage **designs, folders, assets, and comments**.

> Official docs: `https://www.canva.dev/docs/connect/`

---

## When to Use

Use this skill when you need to:

- **List and search designs** in a Canva account
- **Create new designs** (documents, presentations, whiteboards, or custom sizes)
- **Export designs** as PDF, PNG, JPG, or other formats
- **Upload assets** (images, videos) to Canva
- **Manage folders** and organize designs
- **Add comments** to designs for collaboration
- **Get user profile** information

---

## Prerequisites

Go to [vm0.ai](https://vm0.ai) **Settings → Connectors** and connect **Canva**. vm0 will automatically inject the required `CANVA_TOKEN` environment variable.

### Rate Limits

Canva API has per-user rate limits that vary by endpoint. Most read endpoints allow 100 requests/user, write endpoints allow 20-30 requests/user.

---

> **Important:** When using `$VAR` in a command that pipes to another command, wrap the command containing `$VAR` in `bash -c '...'`. Due to a Claude Code bug, environment variables are silently cleared when pipes are used directly.
> ```bash
> bash -c 'curl -s "https://api.example.com" --header "Authorization: Bearer $API_KEY"' | jq '.'
> ```

## How to Use

All examples below assume you have `CANVA_TOKEN` set.

Base URL: `https://api.canva.com/rest/v1`

---

### 1. Get Current User Profile

Get your user profile information:

```bash
bash -c 'curl -s "https://api.canva.com/rest/v1/users/me/profile" --header "Authorization: Bearer $CANVA_TOKEN"' | jq '.profile'
```

---

### 2. List Designs

List designs in your account:

```bash
bash -c 'curl -s "https://api.canva.com/rest/v1/designs?limit=20" --header "Authorization: Bearer $CANVA_TOKEN"' | jq '.items[] | {id, title, created_at, updated_at}'
```

To search designs by query:

```bash
bash -c 'curl -s "https://api.canva.com/rest/v1/designs?query=marketing&limit=10" --header "Authorization: Bearer $CANVA_TOKEN"' | jq '.items[] | {id, title}'
```

Save a design ID from the results for use in subsequent commands.

---

### 3. Get Design Details

Get metadata for a specific design. Replace `<design-id>` with an actual design ID:

```bash
bash -c 'curl -s "https://api.canva.com/rest/v1/designs/<design-id>" --header "Authorization: Bearer $CANVA_TOKEN"' | jq '.design | {id, title, owner, urls, created_at, updated_at, page_count}'
```

---

### 4. Create a New Design

Create a new document:

Write to `/tmp/canva_request.json`:

```json
{
  "design_type": {
    "type": "preset",
    "name": "doc"
  },
  "title": "My New Document"
}
```

Then run:

```bash
bash -c 'curl -s -X POST "https://api.canva.com/rest/v1/designs" --header "Authorization: Bearer $CANVA_TOKEN" --header "Content-Type: application/json" -d @/tmp/canva_request.json' | jq '.design | {id, title, urls}'
```

**Preset names:** `doc`, `presentation`, `whiteboard`

To create a design with custom dimensions (in pixels, 40-8000):

Write to `/tmp/canva_request.json`:

```json
{
  "design_type": {
    "type": "custom",
    "width": 1080,
    "height": 1080
  },
  "title": "Instagram Post"
}
```

Then run:

```bash
bash -c 'curl -s -X POST "https://api.canva.com/rest/v1/designs" --header "Authorization: Bearer $CANVA_TOKEN" --header "Content-Type: application/json" -d @/tmp/canva_request.json' | jq '.design | {id, title, urls}'
```

---

### 5. Export Design as PDF

Export a design as PDF. Replace `<design-id>` with an actual design ID:

Write to `/tmp/canva_request.json`:

```json
{
  "design_id": "<design-id>",
  "format": {
    "type": "pdf",
    "size": "a4"
  }
}
```

Then run:

```bash
bash -c 'curl -s -X POST "https://api.canva.com/rest/v1/exports" --header "Authorization: Bearer $CANVA_TOKEN" --header "Content-Type: application/json" -d @/tmp/canva_request.json' | jq '{id: .job.id, status: .job.status}'
```

Then poll for completion. Replace `<export-id>` with the job ID from above:

```bash
bash -c 'curl -s "https://api.canva.com/rest/v1/exports/<export-id>" --header "Authorization: Bearer $CANVA_TOKEN"' | jq '{status: .job.status, urls: .job.urls}'
```

When status is `success`, download URLs are valid for 24 hours.

---

### 6. Export Design as PNG

Export a design as PNG. Replace `<design-id>` with an actual design ID:

Write to `/tmp/canva_request.json`:

```json
{
  "design_id": "<design-id>",
  "format": {
    "type": "png",
    "width": 1024,
    "transparent_background": true
  }
}
```

Then run:

```bash
bash -c 'curl -s -X POST "https://api.canva.com/rest/v1/exports" --header "Authorization: Bearer $CANVA_TOKEN" --header "Content-Type: application/json" -d @/tmp/canva_request.json' | jq '{id: .job.id, status: .job.status}'
```

Poll with the same export status endpoint as above.

---

### 7. List Design Pages

Get all pages of a design. Replace `<design-id>` with an actual design ID:

```bash
bash -c 'curl -s "https://api.canva.com/rest/v1/designs/<design-id>/pages" --header "Authorization: Bearer $CANVA_TOKEN"' | jq '.items[] | {index: .index, title: .title, width: .width, height: .height}'
```

---

### 8. Create a Folder

Create a new folder to organize designs:

Write to `/tmp/canva_request.json`:

```json
{
  "name": "Marketing Assets",
  "parent_folder_id": "root"
}
```

Then run:

```bash
bash -c 'curl -s -X POST "https://api.canva.com/rest/v1/folders" --header "Authorization: Bearer $CANVA_TOKEN" --header "Content-Type: application/json" -d @/tmp/canva_request.json' | jq '.folder | {id, name}'
```

---

### 9. List Folder Items

List items in a folder. Replace `<folder-id>` with an actual folder ID:

```bash
bash -c 'curl -s "https://api.canva.com/rest/v1/folders/<folder-id>/items?limit=20" --header "Authorization: Bearer $CANVA_TOKEN"' | jq '.items[] | {type, id: .design.id // .folder.id, name: .design.title // .folder.name}'
```

---

### 10. Move Item to Folder

Move a design or folder to another folder. Replace `<item-id>` and `<target-folder-id>`:

Write to `/tmp/canva_request.json`:

```json
{
  "item_id": "<item-id>",
  "to": {
    "folder_id": "<target-folder-id>"
  }
}
```

Then run:

```bash
bash -c 'curl -s -X POST "https://api.canva.com/rest/v1/folders/move" --header "Authorization: Bearer $CANVA_TOKEN" --header "Content-Type: application/json" -d @/tmp/canva_request.json'
```

---

### 11. Get Asset Details

Get metadata for an uploaded asset. Replace `<asset-id>` with an actual asset ID:

```bash
bash -c 'curl -s "https://api.canva.com/rest/v1/assets/<asset-id>" --header "Authorization: Bearer $CANVA_TOKEN"' | jq '.asset | {id, name, tags, created_at, updated_at, thumbnail}'
```

---

### 12. Update Asset

Update an asset's name and tags. Replace `<asset-id>` with an actual asset ID:

Write to `/tmp/canva_request.json`:

```json
{
  "name": "Updated Logo",
  "tags": ["logo", "brand", "2025"]
}
```

Then run:

```bash
bash -c 'curl -s -X PATCH "https://api.canva.com/rest/v1/assets/<asset-id>" --header "Authorization: Bearer $CANVA_TOKEN" --header "Content-Type: application/json" -d @/tmp/canva_request.json' | jq '.asset | {id, name, tags}'
```

---

### 13. Delete Asset

Delete an asset (moves to trash). Replace `<asset-id>` with an actual asset ID:

```bash
bash -c 'curl -s -X DELETE "https://api.canva.com/rest/v1/assets/<asset-id>" --header "Authorization: Bearer $CANVA_TOKEN"'
```

---

### 14. Create Comment Thread

Add a comment to a design. Replace `<design-id>`:

Write to `/tmp/canva_request.json`:

```json
{
  "message": "Can we adjust the colors here to match the brand guidelines?",
  "attached_to": {
    "type": "design"
  }
}
```

Then run:

```bash
bash -c 'curl -s -X POST "https://api.canva.com/rest/v1/designs/<design-id>/comments" --header "Authorization: Bearer $CANVA_TOKEN" --header "Content-Type: application/json" -d @/tmp/canva_request.json' | jq '.thread | {id, message}'
```

---

### 15. Reply to Comment Thread

Reply to an existing comment thread. Replace `<design-id>` and `<thread-id>`:

Write to `/tmp/canva_request.json`:

```json
{
  "message": "Updated the colors. Please review."
}
```

Then run:

```bash
bash -c 'curl -s -X POST "https://api.canva.com/rest/v1/designs/<design-id>/comments/<thread-id>/replies" --header "Authorization: Bearer $CANVA_TOKEN" --header "Content-Type: application/json" -d @/tmp/canva_request.json' | jq '.reply | {id, message}'
```

---

### 16. List Brand Templates

List available brand templates (requires Canva Enterprise):

```bash
bash -c 'curl -s "https://api.canva.com/rest/v1/brand-templates?limit=20" --header "Authorization: Bearer $CANVA_TOKEN"' | jq '.items[] | {id, title, created_at}'
```

---

## Guidelines

- **Async jobs**: Export, import, upload, autofill, and resize operations are asynchronous. Start the job with POST, then poll the status with GET using the returned job ID until `status` is `success` or `failed`.
- **Pagination**: List endpoints return a `continuation` token. Pass it as a query parameter to get the next page of results.
- **Design URLs**: The `urls.edit_url` and `urls.view_url` fields in design responses are valid for 30 days.
- **Export URLs**: Download URLs from export jobs are valid for 24 hours.
- **Custom dimensions**: Width and height must be between 40 and 8000 pixels.
- **Asset uploads**: For binary file uploads, use `Content-Type: application/octet-stream` with an `Asset-Upload-Metadata` header containing base64-encoded name.
- **Rate limits**: Read endpoints: ~100 req/user. Write endpoints: ~20-30 req/user. Export polling: ~120 req/user.

Overview

This skill provides direct curl-based access to the Canva Connect API for managing designs, folders, assets, exports, and comments. It is built for CLI workflows and automation where you have a CANVA_TOKEN available in the environment. Use it to list and search designs, create new canvases, export finished files, upload assets, and manage collaboration threads.

How this skill works

All operations call the Canva REST endpoints under https://api.canva.com/rest/v1 using curl. Examples show how to set request bodies in temporary JSON files, run POST/PATCH/DELETE requests, and poll asynchronous jobs like exports. The provided commands assume CANVA_TOKEN is set and recommend bash -c when piping to tools like jq to avoid environment variable loss.

When to use it

  • List or search designs in a Canva account from scripts or CI
  • Create new designs with presets or custom pixel dimensions
  • Export designs to PDF, PNG, JPG and download completed files
  • Upload, update, or delete image and video assets programmatically
  • Organize designs into folders and move items between folders
  • Add comments or reply to comment threads for collaborative reviews

Best practices

  • Keep CANVA_TOKEN in a secure environment variable and never hard-code it
  • Wrap curl calls in bash -c '...' when piping to jq to preserve env vars
  • Respect rate limits: batch operations and poll export jobs with backoff
  • Use pagination tokens for large lists and limit page sizes to reduce calls
  • Poll asynchronous jobs (exports/uploads) until status is success or failed
  • Encode asset metadata with Asset-Upload-Metadata for binary uploads

Example use cases

  • Automate nightly exports of marketing templates to PDF for distribution
  • Build a script that imports a brand image set into Canva as assets
  • Search for all presentation designs updated this month and archive them
  • Create a custom-sized social post template and share its edit URL
  • Integrate comment creation into a review workflow to leave design notes

FAQ

What headers are required for requests?

All requests require Authorization: Bearer $CANVA_TOKEN. POST/PATCH with JSON also need Content-Type: application/json.

How do I handle export jobs?

Start the export with POST /exports, capture the returned job id, then poll GET /exports/<job-id> until job.status is success or failed. Download URLs are valid for 24 hours.