---
title: Accept user-uploaded images
description: The Direct Creator Upload feature in Cloudflare Images lets your users upload images with a one-time upload URL without exposing your API key or token to the client. Using a direct creator upload also eliminates the need for an intermediary storage bucket and the storage/egress costs associated with it.
image: https://developers.cloudflare.com/dev-products-preview.png
---

[Skip to content](#%5Ftop) 

Was this helpful?

YesNo

[ Edit page ](https://github.com/cloudflare/cloudflare-docs/edit/production/src/content/docs/images/storage/upload-images/direct-creator-upload.mdx) [ Report issue ](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) 

Copy page

# Accept user-uploaded images

The Direct Creator Upload feature in Cloudflare Images lets your users upload images with a one-time upload URL without exposing your API key or token to the client. Using a direct creator upload also eliminates the need for an intermediary storage bucket and the storage/egress costs associated with it.

You can set up [webhooks](https://developers.cloudflare.com/images/storage/upload-images/configure-webhooks/) to receive notifications on your direct creator upload workflow.

## Request a one-time upload URL

Make a `POST` request to the `direct_upload` endpoint using the example below as reference.

Note

The `metadata` included in the request is never shared with end-users.

Terminal window

```

curl --request POST \

https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v2/direct_upload \

--header "Authorization: Bearer <API_TOKEN>" \

--form 'requireSignedURLs=true' \

--form 'metadata={"key":"value"}'


```

After a successful request, you will receive a response similar to the example below. The `id` field is a future image identifier that will be uploaded by a creator.

```

{

  "result": {

    "id": "2cdc28f0-017a-49c4-9ed7-87056c83901",

    "uploadURL": "https://upload.imagedelivery.net/Vi7wi5KSItxGFsWRG2Us6Q/2cdc28f0-017a-49c4-9ed7-87056c83901"

  },

  "result_info": null,

  "success": true,

  "errors": [],

  "messages": []

}


```

Explain Code

After calling the endpoint, a new draft image record is created, but the image will not appear in the list of images. If you want to check the status of the image record, you can make a request to the one-time upload URL using the `direct_upload` endpoint.

## Check the image record status

To check the status of a new draft image record, use the one-time upload URL as shown in the example below.

Terminal window

```

curl https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1/{image_id} \

--header "Authorization: Bearer <API_TOKEN>"


```

After a successful request, you should receive a response similar to the example below. The `draft` field is set to `true` until a creator uploads an image. After an image is uploaded, the draft field is removed.

```

{

  "result": {

    "id": "2cdc28f0-017a-49c4-9ed7-87056c83901",

    "metadata": {

      "key": "value"

    },

    "uploaded": "2022-01-31T16:39:28.458Z",

    "requireSignedURLs": true,

    "variants": [

      "https://imagedelivery.net/Vi7wi5KSItxGFsWRG2Us6Q/2cdc28f0-017a-49c4-9ed7-87056c83901/public",

      "https://imagedelivery.net/Vi7wi5KSItxGFsWRG2Us6Q/2cdc28f0-017a-49c4-9ed7-87056c83901/thumbnail"

    ],

    "draft": true

  },

  "success": true,

  "errors": [],

  "messages": []

}


```

Explain Code

The backend endpoint should return the `uploadURL` property to the client, which uploads the image without needing to pass any authentication information with it.

Below is an example of an HTML page that takes a one-time upload URL and uploads any image the user selects.

```

<!DOCTYPE html>

<html>

  <body>

    <form

      action="INSERT_UPLOAD_URL_HERE"

      method="post"

      enctype="multipart/form-data"

    >

      <input type="file" id="myFile" name="file" />

      <input type="submit" />

    </form>

  </body>

</html>


```

Explain Code

By default, the `uploadURL` expires after 30 minutes if unused. To override this option, add the following argument to the cURL command:

```

--data '{"expiry":"2021-09-14T16:00:00Z"}'


```

The expiry value must be a minimum of two minutes and maximum of six hours in the future.

## Direct Creator Upload with custom ID

You can specify a [custom ID](https://developers.cloudflare.com/images/storage/upload-images/upload-custom-path/) when you first request a one-time upload URL, instead of using the automatically generated ID for your image. Note that images with a custom ID cannot be made private with the [signed URL tokens](https://developers.cloudflare.com/images/optimization/hosted-images/serve-private-images/) feature (`--requireSignedURLs=true`).

To specify a custom ID, pass a form field with the name ID and corresponding custom ID value as shown in the example below.

```

--form 'id=this/is/my-customid'


```

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/images/","name":"Cloudflare Images"}},{"@type":"ListItem","position":3,"item":{"@id":"/images/storage/","name":"Storage"}},{"@type":"ListItem","position":4,"item":{"@id":"/images/storage/upload-images/","name":"Upload images"}},{"@type":"ListItem","position":5,"item":{"@id":"/images/storage/upload-images/direct-creator-upload/","name":"Accept user-uploaded images"}}]}
```
