# Media Handling

Manage your media assets before attaching them to posts. Publer’s API supports direct uploads and URL imports, returning media IDs you can reference when creating or updating posts.

### Overview

Before including media in your social media posts, you must first upload those files to Publer's servers. The API provides two methods for uploading media:

1. Direct file upload
2. Upload from URL

Once uploaded, you'll receive a media ID that can be referenced in your post requests.

### Direct File Upload

Use this method when you have local media files that you want to upload directly.

#### Limitation

* Maximum file size for direct uploads: 200MB per file.
* Requests exceeding 200MB will be rejected (typically with HTTP 413 Payload Too Large). For larger files, use the [Upload from URL](#upload-from-url) method.

#### Request Format

This endpoint expects a `multipart/form-data` request with the file included in the `file` field.

## Upload a media file directly

> Upload a media file (image, video, or document) to be used in social media posts

```json
{"openapi":"3.1.1","info":{"title":"Publer API","version":"1.0.0"},"tags":[{"name":"Media","description":"Endpoints for uploading and managing media files"}],"servers":[{"url":"https://app.publer.com/api/v1"}],"security":[{"BearerApiAuth":[]}],"components":{"securitySchemes":{"BearerApiAuth":{"type":"apiKey","name":"Authorization","in":"header","description":"API key authentication. Format: \"Bearer-API YOUR_API_KEY\""}},"schemas":{"MediaUploadResponse":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the uploaded media"},"path":{"type":"string","description":"URL path to access the uploaded media"},"thumbnail":{"type":"string","description":"URL path to access a thumbnail version of the media"},"validity":{"type":"object","description":"Indicates which networks and post types support this media"},"width":{"type":"number","description":"Width of the media in pixels"},"height":{"type":"number","description":"Height of the media in pixels"},"source":{"type":"string","description":"Source attribution for the media"},"type":{"type":"string","description":"Media type (photo, video, document)"},"name":{"type":"string","description":"Original filename"},"caption":{"type":"string","description":"Caption for the media"}}},"ErrorResponse":{"type":"object","properties":{"errors":{"type":"array","description":"List of error messages","items":{"type":"string"}}}},"401ErrorResponse":{"type":"object","properties":{"errors":{"type":"array","description":"List of error messages","items":{"type":"string"}}}},"403ErrorResponse":{"type":"object","properties":{"errors":{"type":"array","description":"List of error messages","items":{"type":"string"}}}}}},"paths":{"/media":{"post":{"summary":"Upload a media file directly","description":"Upload a media file (image, video, or document) to be used in social media posts","tags":["Media"],"parameters":[{"schema":{"type":"string"},"name":"Publer-Workspace-Id","in":"header","description":"ID of the workspace to upload media","required":true}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream"},"direct_upload":{"type":"boolean","description":"Whether to upload directly to our S3 cloud (slower, but required if you need the final media URL)","default":false},"in_library":{"type":"boolean","description":"Whether to save to media library","default":false}}},"encoding":{"file":{"contentType":"application/octet-stream"}}}}},"responses":{"200":{"description":"Media file uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaUploadResponse"}}}},"400":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/401ErrorResponse"}}}},"413":{"description":"Permission denied or missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/403ErrorResponse"}}}}}}}}}
```

**Key Response Fields**

| Field             | Description                                                          |
| ----------------- | -------------------------------------------------------------------- |
| `id`              | Unique identifier for the uploaded media (use this in post requests) |
| `path`            | URL path to access the uploaded media                                |
| `thumbnail`       | URL path to access a thumbnail version of the media                  |
| `validity`        | Indicates which networks and post types support this media           |
| `width`, `height` | Dimensions of the uploaded media in pixels                           |
| `type`            | Media type (photo, video, document)                                  |
| `name`            | Original filename                                                    |

### Upload from URL

Use this method when your media is already hosted elsewhere and you want to import it by URL.

## Upload media from URL

> Upload media files by providing URLs

```json
{"openapi":"3.1.1","info":{"title":"Publer API","version":"1.0.0"},"tags":[{"name":"Media","description":"Endpoints for uploading and managing media files"}],"servers":[{"url":"https://app.publer.com/api/v1"}],"security":[{"BearerApiAuth":[]}],"components":{"securitySchemes":{"BearerApiAuth":{"type":"apiKey","name":"Authorization","in":"header","description":"API key authentication. Format: \"Bearer-API YOUR_API_KEY\""}},"schemas":{"ErrorResponse":{"type":"object","properties":{"errors":{"type":"array","description":"List of error messages","items":{"type":"string"}}}},"401ErrorResponse":{"type":"object","properties":{"errors":{"type":"array","description":"List of error messages","items":{"type":"string"}}}},"403JobErrorResponse":{"type":"object","properties":{"errors":{"type":"array","description":"List of error messages","items":{"type":"string"}}}},"MediaFromUrlRequest":{"type":"object","required":["media","type"],"properties":{"media":{"type":"array","description":"List of media URLs and metadata","items":{"type":"object","required":["url","name"],"properties":{"url":{"type":"string","description":"URL of the media to download"},"name":{"type":"string","description":"Custom name for the media file"},"caption":{"type":"string","description":"Caption for the media"},"source":{"type":"string","description":"Source attribution for the media"}}}},"type":{"type":"string","description":"Upload type","enum":["single","thumbnail","bulk","thumbnail"]},"direct_upload":{"type":"boolean","description":"Whether to upload directly to our S3 cloud (slower, but required if you need the final media URL)","default":false},"in_library":{"type":"boolean","description":"Whether to save to media library","default":false}}}}},"paths":{"/media/from-url":{"post":{"summary":"Upload media from URL","description":"Upload media files by providing URLs","tags":["Media"],"parameters":[{"schema":{"type":"string"},"name":"Publer-Workspace-Id","in":"header","description":"ID of the workspace to upload media","required":true}],"responses":{"200":{"description":"Media upload job created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string","description":"ID of the created job"}}}}}},"400":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/401ErrorResponse"}}}},"403":{"description":"Permission denied or missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/403JobErrorResponse"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaFromUrlRequest"}}},"description":"URL upload request","required":true}}}}}
```

**Request Parameters**

<table data-header-hidden><thead><tr><th width="164.66632080078125"></th><th width="503.065673828125"></th><th></th></tr></thead><tbody><tr><td>Parameter</td><td>Description</td><td>Required</td></tr><tr><td><code>media[].url</code></td><td>URL of the media file to download</td><td>Yes</td></tr><tr><td><code>media[].name</code></td><td>Custom name for the media file</td><td>Yes</td></tr><tr><td><code>media[].caption</code></td><td>Caption for the media</td><td>No</td></tr><tr><td><code>media[].source</code></td><td>Source attribution</td><td>No</td></tr><tr><td><code>type</code></td><td>Upload type (<code>single</code> or <code>bulk</code>)</td><td>No</td></tr><tr><td><code>direct_upload</code></td><td><p>Whether to upload directly to our S3 cloud (slower, but required if you need the final media URL)</p><p>(default: <code>false</code>)</p></td><td>No</td></tr><tr><td><code>in_library</code></td><td>Whether to save to media library (default: <code>false</code>)</td><td>No</td></tr></tbody></table>

Unlike direct uploads, URL uploads are processed asynchronously. Use the returned `job_id` to check the status of your upload.

#### Checking Upload Status

## Get job status

> Check the status of an asynchronous job, including URL media uploads

```json
{"openapi":"3.1.1","info":{"title":"Publer API","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Endpoints for managing asynchronous jobs"}],"servers":[{"url":"https://app.publer.com/api/v1"}],"security":[{"BearerApiAuth":[]}],"components":{"securitySchemes":{"BearerApiAuth":{"type":"apiKey","name":"Authorization","in":"header","description":"API key authentication. Format: \"Bearer-API YOUR_API_KEY\""}},"schemas":{"JobStatusResponse":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the request was successful"},"data":{"type":"object","properties":{"status":{"type":"string","enum":["working","complete","failed"],"description":"Current status of the job \n\n - `working`: The job is still processing.\n - `complete`: The job has completed successfully.\n - `failed`: The job has failed."},"result":{"type":"object","description":"Result data, contents depend on job type","properties":{"status":{"type":"string","enum":["working","complete","failed"],"description":"Current status of the job \n\n - `working`: The job is still processing.\n - `complete`: The job has completed successfully.\n - `failed`: The job has failed."},"payload":{"type":"object","description":"Result payload containing any operation results","properties":{"failures":{"type":"object","description":"Any failures that occurred during processing"}}},"plan":{"type":"object","description":"Current user's plan information","properties":{"rate":{"type":"string","description":"The rate plan of the workspace"},"locked":{"type":"boolean","description":"Whether the workspace is locked"}}}}}}}}},"401ErrorResponse":{"type":"object","properties":{"errors":{"type":"array","description":"List of error messages","items":{"type":"string"}}}},"403ErrorResponse":{"type":"object","properties":{"errors":{"type":"array","description":"List of error messages","items":{"type":"string"}}}}}},"paths":{"/job_status/{job_id}":{"get":{"summary":"Get job status","description":"Check the status of an asynchronous job, including URL media uploads","tags":["Jobs"],"parameters":[{"schema":{"type":"string"},"name":"Publer-Workspace-Id","in":"header","description":"ID of the workspace to retrieve posts from","required":true},{"schema":{"type":"string"},"name":"job_id","in":"path","description":"ID of the job to check","required":true}],"responses":{"200":{"description":"Job status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/401ErrorResponse"}}}},"403":{"description":"Permission denied or missing required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/403ErrorResponse"}}}}}}}}}
```

### Using Media in Posts

Once you've uploaded media and have the media ID, you can reference it in your post requests:

```json
{
  "bulk": {
    "state": "scheduled",
    "posts": [
      {
        "networks": {
          "default": {
            "type": "photo",
            "text": "Check out our latest product!",
            "media": [
              {
                "id": "6813892b5ec8b1e65235ae9e",
                "type": "image",
                "alt_text": "Product on white background"
              }
            ]
          }
        },
        "accounts": [
          {
            "id": "66db83154e299efa19a2d8eb",
            "scheduled_at": "2025-05-15T14:30:00Z"
          }
        ]
      }
    ]
  }
}
```

### Supported Media Types

#### Images

* **Supported formats**: JPG, PNG, GIF, WEBP
* **Recommended dimensions**: Varies by platform (see [Networks Reference](https://publer.com/docs/posting/create-posts/networks))
* **Maximum file size**: Varies by platform, generally 5-10MB

#### Videos

* **Supported formats**: MP4, MOV, AVI, WEBM
* **Recommended dimensions**: Varies by platform (see [Networks Reference](https://publer.com/docs/posting/create-posts/networks))
* **Maximum file size**: Varies by platform, generally 512MB-2GB
* **Duration limits**: Varies by platform and content type

#### Documents

* **Supported formats**: PDF
* **Maximum file size**: 100MB
* **Supported networks**: LinkedIn only

### Network Validation

The `validity` object in the media upload response indicates which networks and post types can use the uploaded media. This helps prevent errors when attempting to use incompatible media in your posts.

For example, if `validity.instagram.reel` is `false`, the uploaded media cannot be used for Instagram Reels.

### Best Practices

#### Image Optimization

1. **Resolution**: Use appropriate image resolutions for each platform
2. **Aspect ratio**: Follow recommended aspect ratios to avoid cropping
3. **File size**: Optimize images for web to reduce file size
4. **Alt text**: Always include descriptive alt text for accessibility

#### Video Optimization

1. **Format**: Use MP4 with H.264 encoding for maximum compatibility
2. **Dimensions**: Use 1080p (1920x1080) for standard videos
3. **Aspect ratio**: 16:9 for horizontal, 9:16 for vertical/stories/reels
4. **Duration**: Keep videos under platform limits
5. **Thumbnails**: Consider uploading custom thumbnails for videos

#### General Tips

1. **Pre-check compatibility**: Review the `validity` object before using media
2. **Error handling**: Implement robust error handling for upload failures
3. **Caching**: Cache media IDs to avoid unnecessary re-uploads

### Related Topics

* [Content Types](https://publer.com/docs/posting/create-posts/content-types) - Details on different content formats
* [Network Reference](https://publer.com/docs/posting/create-posts/networks) - Platform-specific media requirements
* [Publishing Methods](https://publer.com/docs/posting/create-posts/publishing-methods) - Using media in different post types
