# Bulk Create Studio Templates

> Create multiple studio templates at once via CSV or JSON

- **URL**: https://orshot.com/docs/api-reference/enterprise-template-bulk-create

---

Create multiple studio templates in a single API call. This endpoint is ideal for importing templates in bulk from external systems or migrating existing template libraries.

For detailed information about the template data structure, see [Anatomy of a Template](https://orshot.com/docs/definitions/template-anatomy).

## Endpoint```markdown tab="Endpoint"
https://api.orshot.com/v1/studio/templates/bulk-create
```## Query Parameters

| Parameter           | Type    | Required | Default | Description                                                                                                                                                                                                                                               |
| ------------------- | ------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `includeThumbnails` | Boolean | No       | `false` | When `true`, thumbnails for every page of every template are rendered before the response is sent. Templates are processed sequentially to bound concurrency; expect ~1–2 seconds per page. When `false` or absent, thumbnails are generated in the background. |

## Request

<Tabs items=>
<Tab value="JSON Request">```js
await fetch("https://api.orshot.com/v1/studio/templates/bulk-create", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer <ORSHOT_API_KEY>",
  },
  body: JSON.stringify({
    templates: [
      {
        name: "Instagram Post - Square",
        description: "1:1 aspect ratio for Instagram feed",
        canvas_width: 1080,
        canvas_height: 1080
      },
      {
        name: "Instagram Story",
        description: "9:16 aspect ratio for Instagram stories",
        canvas_width: 1080,
        canvas_height: 1920
      },
      {
        name: "Facebook Cover",
        description: "Facebook page cover photo",
        canvas_width: 820,
        canvas_height: 312
      },
      {
        name: "Twitter Header",
        description: "Twitter profile header image",
        canvas_width: 1500,
        canvas_height: 500
      },
      {
        name: "LinkedIn Banner",
        description: "LinkedIn company page banner",
        canvas_width: 1128,
        canvas_height: 191
      }
    ]
  }),
});
```</Tab>
<Tab value="Response">```json
{
  "success": true,
  "created": 5,
  "failed": 0,
  "templates": [
    {
      "id": 12345,
      "name": "Instagram Post - Square",
      "canvas_width": 1080,
      "canvas_height": 1080
    },
    {
      "id": 12346,
      "name": "Instagram Story",
      "canvas_width": 1080,
      "canvas_height": 1920
    },
    {
      "id": 12347,
      "name": "Facebook Cover",
      "canvas_width": 820,
      "canvas_height": 312
    },
    {
      "id": 12348,
      "name": "Twitter Header",
      "canvas_width": 1500,
      "canvas_height": 500
    },
    {
      "id": 12349,
      "name": "LinkedIn Banner",
      "canvas_width": 1128,
      "canvas_height": 191
    }
  ]
}
```</Tab>
<Tab value="Response (?includeThumbnails=true)">```json
{
  "success": true,
  "created": 2,
  "failed": 0,
  "templates": [
    {
      "id": 12345,
      "name": "Instagram Post - Square",
      "canvas_width": 1080,
      "canvas_height": 1080,
      "thumbnails": {
        "success": true,
        "pages": [
          {
            "page": 1,
            "page_id": "page-1-uuid",
            "thumbnail_url": "https://storage.orshot.com/cloud/w-50/renders/thumbnails/a1b2c3.png",
            "error": null
          }
        ]
      }
    },
    {
      "id": 12346,
      "name": "Instagram Story",
      "canvas_width": 1080,
      "canvas_height": 1920,
      "thumbnails": {
        "success": true,
        "pages": [
          {
            "page": 1,
            "page_id": "page-2-uuid",
            "thumbnail_url": "https://storage.orshot.com/cloud/w-50/renders/thumbnails/d4e5f6.png",
            "error": null
          }
        ]
      }
    }
  ]
}
```</Tab>
<Tab value="Error Response">```json
{
  "success": true,
  "created": 3,
  "failed": 2,
  "templates": [
    {
      "id": 12345,
      "name": "Valid Template 1",
      "canvas_width": 1080,
      "canvas_height": 1080
    },
    {
      "id": 12346,
      "name": "Valid Template 2",
      "canvas_width": 1200,
      "canvas_height": 628
    },
    {
      "id": 12347,
      "name": "Valid Template 3",
      "canvas_width": 800,
      "canvas_height": 600
    }
  ],
  "errors": [
    {
      "index": 3,
      "name": "Invalid Template",
      "errors": ["'canvas_width' must be between 1 and 8192"]
    },
    {
      "index": 4,
      "name": "Another Invalid",
      "errors": ["'name' is required and must be a string"]
    }
  ]
}
```</Tab>
</Tabs>

## Rate Limits

| Limit                     | Value |
| ------------------------- | ----- |
| Requests per minute       | 30    |
| Max templates per request | 50    |

## Request Body Parameters

| Parameter   | Type  | Required | Description                         |
| ----------- | ----- | -------- | ----------------------------------- |
| `templates` | Array | Yes      | Array of template objects to create |

### Template Object Structure

Each template in the `templates` array should include:

| Field           | Type    | Required | Description                               |
| --------------- | ------- | -------- | ----------------------------------------- |
| `name`          | String  | Yes      | Name of the template (max 255 characters) |
| `description`   | String  | No       | Description of the template               |
| `canvas_width`  | Integer | Yes      | Width of the canvas in pixels (1-5000)    |
| `canvas_height` | Integer | Yes      | Height of the canvas in pixels (1-5000)   |
| `pages_data`    | Array   | No       | Array of page objects with elements       |
| `thumbnail_url` | String  | No       | URL to a thumbnail image                  |

## Response Fields

| Field       | Type    | Description                                                      |
| ----------- | ------- | ---------------------------------------------------------------- |
| `success`   | Boolean | Whether the operation completed (may be partial success)         |
| `created`   | Integer | Number of templates successfully created                         |
| `failed`    | Integer | Number of templates that failed validation                       |
| `templates` | Array   | Array of successfully created template summaries                 |
| `errors`    | Array   | Array of error objects for failed templates (only if any failed) |

### Error Object Structure

| Field    | Type    | Description                                        |
| -------- | ------- | -------------------------------------------------- |
| `index`  | Integer | Index of the failed template in the original array |
| `name`   | String  | Name of the template that failed                   |
| `errors` | Array   | List of validation error messages                  |

### Thumbnails Object Structure

When you pass `?includeThumbnails=true`, each entry in `templates[]` gets a nested `thumbnails` object with per-page render results:

| Field                   | Type         | Description                                                                   |
| ----------------------- | ------------ | ----------------------------------------------------------------------------- |
| `success`               | Boolean      | `true` if at least one page of this template rendered successfully            |
| `pages[].page`          | Integer      | 1-based page number                                                           |
| `pages[].page_id`       | String       | Stable UUID of the page                                                       |
| `pages[].thumbnail_url` | String\|null | Public URL of the uploaded thumbnail PNG. `null` if this page failed          |
| `pages[].error`         | String\|null | Error message if this page failed. `null` on success                          |

When `?includeThumbnails` is not passed, thumbnails are generated asynchronously after the response is sent and appear on the template (via `pages_data[].thumbnail_url` and `pages_meta[].thumbnail_url`) shortly after creation.

## Bulk Import with Pages Data

You can also include full page structures with elements for each template:```js
await fetch("https://api.orshot.com/v1/studio/templates/bulk-create", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer <ORSHOT_API_KEY>",
  },
  body: JSON.stringify({
    templates: [
      {
        name: "Product Card A",
        canvas_width: 800,
        canvas_height: 600,
        pages_data: [
          {
            id: "page-uuid-1",
            name: "Page 1",
            canvas: { width: 800, height: 600, backgroundColor: "#f5f5f5" },
            elements: [
              {
                id: "title-1",
                type: "text",
                x: 50,
                y: 50,
                width: 700,
                height: 60,
                content: "Product Title",
                parameterId: "title",
                parameterizable: true,
              },
            ],
          },
        ],
      },
      {
        name: "Product Card B",
        canvas_width: 800,
        canvas_height: 600,
        pages_data: [
          {
            id: "page-uuid-2",
            name: "Page 1",
            canvas: { width: 800, height: 600, backgroundColor: "#ffffff" },
            elements: [
              {
                id: "title-2",
                type: "text",
                x: 50,
                y: 50,
                width: 700,
                height: 60,
                content: "Product Title",
                parameterId: "title",
                parameterizable: true,
              },
            ],
          },
        ],
      },
    ],
  }),
});
```## Error Responses

| Status Code | Error                           | Description                                              |
| ----------- | ------------------------------- | -------------------------------------------------------- |
| 400         | Validation failed               | `templates` array is missing, empty, or exceeds 50 items |
| 400         | All templates failed validation | Every template in the array had validation errors        |
| 403         | Access Forbidden                | Invalid or missing API key                               |
| 429         | Rate limit exceeded             | Too many requests (max 30/min)                           |
| 500         | Internal server error           | Server-side error                                        |

## Best Practices

1. **Batch Size**: While the limit is 50 templates per request, we recommend batches of 20-30 for optimal performance
2. **Validation**: Validate your data client-side before sending to avoid partial failures
3. **Error Handling**: Always check both `created` and `failed` counts in the response
4. **Idempotency**: This endpoint creates new templates each time - there's no upsert functionality
5. **Pages Data**: If importing templates with complex structures, ensure `pages_data` follows the Orshot Studio format