---
title: "Store a creative from a URL"
method: POST
path: "/workspaces/{workspace}/admin/creatives/from-url"
tags: ["Creative"]
---

# Store a creative from a URL

`POST /workspaces/{workspace}/admin/creatives/from-url`

## Request

- Base URL: `https://plainrouter.com/api/v1`
- URL: `https://plainrouter.com/api/v1/workspaces/{workspace}/admin/creatives/from-url`
- Auth: HTTP bearer

Store a creative in the credential-bound workspace. Set generator, generator_job and parent_creative tags for output from an outside tool.

## Path parameters

- `workspace` integer, required

## Request body

- object
  - `url` string, required: Vetted HTTPS URL to fetch; private addresses and unsafe redirects are refused.
  - `tags` object: Optional flat map of at most 32 string tags; reserved keys count toward the cap. For a creative from an outside tool, set generator and generator_job, plus parent_creative for a variation. Values are stored unchanged. PlainRouter’s own creative tools will set these on every creative they make; intake performs no generation, rendering or scoring.
    - `generator` string: Lowercase slug naming the outside tool that made the creative.
    - `generator_job` string: Printable characters naming the tool’s job or render; control and other non-printable characters are refused.
    - `parent_creative` string: The id returned by the creative APIs: a lowercase ULID of an existing creative in the same workspace that this creative varies.
  - `source_ref` string, nullable

## Response `201`

Creative stored, or the existing creative returned for identical bytes in this workspace.

- CreativeIntakeRead
  - `creative` object, required
    - `id` string, required
    - `fingerprint` string, required
    - `type` 'image' | 'video', required
    - `mime_type` string, required
    - `byte_size` integer, required
    - `width` integer, nullable, required
    - `height` integer, nullable, required
    - `aspect_ratio` number, nullable, required
    - `duration_ms` integer, nullable, required
    - `original_filename` string, nullable
    - `source_ref` string, nullable, required
    - `tags` union, required: Stored tags, including provenance when supplied. An empty map is returned as an empty array. Existing creatives keep their original tags.
      - object
      - string[]
    - `status` 'draft' | 'approved' | 'retired', required
    - `created_at` string, nullable, required
    - `updated_at` string, nullable, required

## Other responses

- `401`: A valid workspace-bound credential is required.
- `403`: The credential or workspace grant does not authorize creative intake.
- `404`: Creative intake is disabled, or the workspace is missing or inaccessible.
- `413`: Creative bytes exceed the 4 GiB cap, or POST data exceeds the request limit.
- `422`: A reserved tag that violates the provenance contract returns error.code creative_provenance_invalid and error.message naming the key. Other intake refusals return their stable error.code and error.message; request-shape errors return message plus field errors.

---

[API](https://skmtc.dev/plainrouter/apis/plainrouter-conversion-api.md) · [All operations](https://skmtc.dev/plainrouter/apis/plainrouter-conversion-api/llms.txt) · [OpenAPI document](https://skmtc.dev/plainrouter/apis/plainrouter-conversion-api/revisions/d071d4f4f05c?raw)
