> ## Documentation Index
> Fetch the complete documentation index at: https://docs.makelocalads.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Image uploads

> Upload a local image once and use its durable URL in any later request.

Some requests take image URLs: a product's `image_urls`, a Quick Shoot's
`direction.image_urls`, a template's `image_urls`, a moodboard's
`reference_image_urls`. When an image is on your computer or a private server,
upload it first and keep the returned `url`.

**Endpoint:** `POST https://makelocalads.com/api/v1/uploads/images`
**Permission:** `images:upload`

## Upload an image

Send one file at a time using multipart form data:

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl --request POST \
    --url "https://makelocalads.com/api/v1/uploads/images" \
    --header "Authorization: Bearer $LOCALADS_API_KEY" \
    --form "file=@/path/to/serum-front.jpg"
  ```

  ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import { readFile } from "node:fs/promises";

  const form = new FormData();
  form.append(
    "file",
    new Blob([await readFile("/path/to/serum-front.jpg")], { type: "image/jpeg" }),
    "serum-front.jpg",
  );

  const response = await fetch(
    "https://makelocalads.com/api/v1/uploads/images",
    {
      method: "POST",
      headers: { Authorization: `Bearer ${process.env.LOCALADS_API_KEY}` },
      body: form,
    },
  );

  if (!response.ok) throw new Error(await response.text());
  const uploadedImage = await response.json();
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import os
  import requests

  with open("/path/to/serum-front.jpg", "rb") as file:
      response = requests.post(
          "https://makelocalads.com/api/v1/uploads/images",
          headers={"Authorization": f"Bearer {os.environ['LOCALADS_API_KEY']}"},
          files={"file": ("serum-front.jpg", file, "image/jpeg")},
      )

  uploaded = response.json()
  print(uploaded["url"])
  ```
</CodeGroup>

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "url": "https://assets.makelocalads.com/public-api/example/images/3a4c79b4-999b-48c2-a77c-1db08b884908.jpg",
  "content_type": "image/jpeg",
  "width": 1600,
  "height": 1600,
  "size_bytes": 428310
}
```

## Usage notes

* One JPG, PNG, WebP, HEIC, or HEIF image per request, up to 10 MB.
* The returned `url` is durable: place it in any `image_urls` array, including
  in a later request. To add several images, repeat the upload once per file.
* Do not send base64 or a JSON data URL.
* An image already available at a public HTTPS URL can be placed directly in
  `image_urls`; LocalAds validates it and keeps its own copy. For
  third-party URLs, the image must work without cookies or authorization
  headers.

| Status | Meaning |
| - | - |
| 413 | The uploaded image is larger than 10 MB |
| 415 | The multipart body or uploaded file is not a supported image type |
| 500 | The upload could not be stored because of a temporary server error; retry |

See [Errors and retries](/concepts/errors) for the error format.
