# Create Image

Registers a new image from a publicly accessible URL, optionally tagging it. The image is downloaded, validated against the supported formats and size limits, and processed asynchronously in the background.
            
## Authentication
            
Requires a valid API key in the X-API-KEY header.
            
## Request Body
            
json
{
  "url": "https://example.com/images/product.jpg",
  "tags": ["ecommerce", "catalog", "summer-2024"]
}

            
### URL Field (Required)
            
The URL must meet the following requirements:
            
Valid URL formats:
- Must be a valid HTTP or HTTPS URL
- Must be absolute (e.g., https://example.com/image.jpg)
- Relative URLs are NOT supported (e.g., /images/photo.jpg)
- The filename will be automatically extracted from the URL path
            
Examples of valid URLs:

https://example.com/product.jpg
https://cdn.example.com/images/2024/photo.png
http://assets.example.com/catalog/item_123.gif

            
Examples of invalid URLs:

/images/product.jpg                    (relative URL)
example.com/image.jpg                   (missing protocol)
ftp://server.com/file.jpg              (FTP not supported)
https://example.com/page.html          (not a supported image extension)
https://example.com/product            (no extension to derive the file type from)

            
URL validation rules:
- Maximum length: 2048 characters
- The URL must be publicly accessible (no authentication supported)
- The host must resolve to a public address. URLs pointing at loopback, private ranges or the
  cloud metadata endpoint are rejected
- The URL is probed with a HEAD request; anything other than a 2xx is rejected
            
### Tags Field (Optional)
            
Optional array of strings to categorize and organize your images.
            
Rules:
- Each tag cannot be empty or contain only whitespace
- Tags are case-sensitive
- Tags are stored as a single comma-separated string, so a tag containing a comma is read back as
  several tags. Avoid commas inside a tag
- There is no explicit limit on the number of tags, but the whole comma-separated list must fit in
  64 KB of storage
            
Example:
json
{
  "url": "https://example.com/logo.png",
  "tags": ["branding", "corporate", "logo", "2024"]
}

            
## Supported Image Formats
            
The file type is taken from the URL's file extension, and the Content-Type header returned by the
URL is validated independently against the list of accepted image media types:
            
### Fully Supported Formats
            
| Format | Extension | Accepted Content-Type | Notes |
|--------|-----------|-----------------------|-------|
| JPEG | .jpg, .jpeg | image/jpeg | Standard and progressive JPEG |
| PNG | .png | image/png | PNG-8, PNG-24, PNG-32 with transparency |
| GIF | .gif | image/gif | Static and animated GIF |
| TIFF | .tif, .tiff | image/tiff, image/x-tiff | Single and multi-page TIFF |
| WebP | .webp | image/webp | Lossy and lossless compression |
| PSD | .psd | image/vnd.adobe.photoshop, image/photoshop, image/psd, application/octet-stream | Adobe Photoshop files |
            
### Content-Type Validation
            
1. The URL must return a Content-Type header
2. The Content-Type must be one of the accepted media types listed above
3. application/octet-stream is only accepted for .psd files — many servers are misconfigured
   and return this generic type for Photoshop files
4. Apart from that application/octet-stream rule, the Content-Type is not cross-checked
   against the file extension: a URL ending in .jpg that serves image/png is accepted, and the
   image is registered with file type jpg
            
Examples of valid Content-Type responses:

Content-Type: image/jpeg          → ✅ Accepted
Content-Type: image/png           → ✅ Accepted
Content-Type: image/gif           → ✅ Accepted
Content-Type: application/octet-stream with .psd extension → ✅ Accepted

            
Examples of invalid Content-Type responses:

Content-Type: text/html           → ❌ Rejected (not an image)
Content-Type: application/pdf     → ❌ Rejected (not supported)
Content-Type: application/octet-stream with .jpg extension → ❌ Rejected
(no Content-Type header)          → ❌ Rejected (missing header)

            
## Image Size and Weight Limits
            
The system automatically validates downloaded images:
            
### File Size Limits
- Maximum file size: 250 MB (262,144,000 bytes)
- Files larger than this limit will be rejected with a validation error
            
### Dimension Limits
- Maximum width: 30,000 pixels
- Maximum height: 30,000 pixels
- Images exceeding these dimensions will be rejected
            
## Response
            
### Success Response (201 Created)
            
Returns the reference (filename) of the created image, wrapped in the house entity envelope. The
reference is the public, tenant-unique key; the numeric id is internal only and is not exposed:
            
json
{
  "value": {
    "reference": "product-123.jpg"
  },
  "@readLink": "https://api2.saleslayer.com/dam/images",
  "@editLink": "https://api2.saleslayer.com/dam/images"
}

            
A Location header points at the new resource, as an absolute URL —
https://api2.saleslayer.com/dam/images(product-123.jpg).
            
Note that on a create, the @readLink/@editLink annotations echo the URL this request was posted
to — the collection, not the new image. Use the Location header to address the created resource.
They are only emitted when hypermedia enrichment is configured for the deployment.
            
The image will be processed asynchronously in the background: it is created with status Up and
the worker moves it to Ok or Er, filling in the dimensions and thumbnail URLs.
            
To check the processing status and retrieve full image details:

GET /images(product-123.jpg)

            
## Error Responses
            
### 400 Bad Request
            
Validation failures are returned in the shared envelope. Service-level messages carry no field
context, so they are grouped under a generic error key:
            
json
{
  "validationFailures": {
    "error": ["URL is required"]
  }
}

            
The messages you can receive, verbatim:
            
| Cause | Message |
|-------|---------|
| Missing or empty URL | URL is required |
| URL over 2048 characters | URL exceeds maximum length of 2048 characters |
| Not an absolute URL | URL is not valid |
| Scheme other than HTTP/HTTPS | URL must use HTTP or HTTPS protocol |
| No extension in the URL path | Could not determine file type from URL. Please ensure the URL contains a filename with an extension. |
| Unsupported extension | File extension 'pdf' is not allowed. Allowed extensions: jpg, jpeg, png, gif, tif, tiff, psd, webp |
| Host is not publicly routable | URL host 'localhost' is not allowed. |
| URL not reachable (non-2xx HEAD) | URL is not accessible. HTTP status: 404 Not Found |
| No Content-Type header | URL does not return a valid Content-Type header |
| application/octet-stream for a non-PSD file | URL returns generic Content-Type (application/octet-stream) for non-PSD file. Extension detected: jpg |
| Unsupported Content-Type | URL does not return an image Content-Type. Received: text/html. Allowed types: image/jpeg, image/png, ... |
| Empty file | The uploaded file is empty |
| File too large | Image file size (300.00 MB) exceeds maximum allowed size of 250 MB |
| Dimensions unreadable | Could not read image dimensions from the uploaded file. Ensure it is a valid image in a supported format. |
| Image too wide | Image width (35000px) exceeds maximum allowed width of 30000px |
| Image too tall | Image height (35000px) exceeds maximum allowed height of 30000px |
| Empty or whitespace-only tag | Tags cannot contain empty values |
            
### 401 Unauthorized
            
Missing or invalid API key in the X-API-KEY header. Emitted by the API gateway:
            
json
{
  "message": "Unauthorized",
  "request_id": "d8aafa5b8f3e400b60bea0123dd33317"
}

            
Quote request_id when contacting support about a rejected request.
            
### 403 Forbidden
            
The API key does not have write permissions for this operation. Same body shape as the 401.
            
### 409 Conflict
            
Two distinct causes, both using the conflict envelope:
            
An image with the same filename (reference) already exists for this tenant:
            
json
{
  "error": "An image with the filename 'product-123.jpg' already exists"
}

            
The tenant has reached its image-library quota:
            
json
{
  "error": "Image library limit reached. Current: 5000, Maximum: 5000"
}

            
Images in status Dv (deleted) do not count towards the quota. Delete unused images to free
capacity, or contact Sales Layer to raise the limit.
            
### 500 Internal Server Error
            
Technical errors such as:
- Network connectivity issues reaching the source URL, or a download timeout (30s)
- Storage service unavailable
- Database errors
            
Note that a source URL that responds with a non-2xx status is a 400, not a 500 — only transport
failures and timeouts land here. The body identifies the request for support:
            
json
{
  "error": "Please contact the administrator of this application by supplying the following code: 0HNF1A2B3C4D5"
}

            
## Complete Example
            
Request:
http
POST /images HTTP/1.1
Host: api2.saleslayer.com
X-API-KEY: your-api-key-here
Content-Type: application/json
            
{
  "url": "https://cdn.example.com/products/summer-2024/product-123.jpg",
  "tags": ["ecommerce", "summer-collection", "featured", "new-arrival"]
}

            
Success Response:
http
HTTP/1.1 201 Created
Content-Type: application/json
Location: https://api2.saleslayer.com/dam/images(product-123.jpg)
            
{
  "value": {
    "reference": "product-123.jpg"
  }
}

            
Checking the result:
http
GET /images(product-123.jpg) HTTP/1.1
Host: api2.saleslayer.com
X-API-KEY: your-api-key-here

            
Result after processing:
json
{
  "value": {
    "id": 12345,
    "reference": "product-123.jpg",
    "status": "Ok",
    "fileType": "jpg",
    "width": 1920,
    "height": 1080,
    "sizeInBytes": 245760,
    "numLinks": 5,
    "tags": ["ecommerce", "summer-collection", "featured", "new-arrival"],
    "originalUrl": "https://cdn.example.com/product-123.jpg",
    "thumbnailUrl": "https://cdn.example.com/product-123_TH.jpg",
    "thumbnailMediumUrl": "https://cdn.example.com/product-123_THM.jpg",
    "thumbnailPreviewUrl": "https://cdn.example.com/product-123_THP.jpg",
    "createdOn": "2024-04-02T10:30:00",
    "modifiedOn": "2024-04-02T10:30:15"
  }
}

Endpoint: POST /images
Version: 2.0.0

## Header parameters:

  - `X-API-KEY` (string, required)
    Tenant's API key (required)

## Request fields (application/json):

  - `url` (string,null)
    Publicly accessible HTTP or HTTPS URL of the image to import. Required. Must be absolute and end
in a supported extension (jpg, jpeg, png, gif, tif, tiff, psd, webp); the image's reference
is the filename taken from the URL path. Maximum 2048 characters.

  - `tags` (array,null)
    Optional tags to associate with the image, e.g. ["product", "catalog", "2024"]. Tags are
case-sensitive and cannot be empty or whitespace. Avoid commas inside a tag — tags are stored as a
comma-separated string and would be read back split.

## Response 201 fields (application/json):

  - `value` (object)
    The reference of a newly created image. Retrieve the full image with
GET /images({reference}); processing runs asynchronously, so the image starts in status
Up and moves to Ok or Er.

  - `value.reference` (string,null)
    The image's filename, unique per tenant. This is the public key used to address the image.

  - `@readLink` (string,null)
    The URL this request was posted to (the collection), not the created image — use the
Location header for that. Present only when hypermedia enrichment is enabled.

  - `@editLink` (string,null)
    The URL this request was posted to (the collection), not the created image — use the
Location header for that. Present only when hypermedia enrichment is enabled.

## Response 400 fields (application/json):

  - `validationFailures` (object,null)

## Response 401 fields (application/json):

  - `message` (string,null)
    Error description, e.g. Unauthorized.

  - `request_id` (string,null)
    Gateway request identifier, to quote when contacting support.

## Response 403 fields (application/json):

  - `message` (string,null)

  - `request_id` (string,null)

## Response 409 fields (application/json):

  - `error` (string,null)

## Response 500 fields (application/json):

  - `error` (string,null)

  - `details` (any,null)


