WordPress API media/new returns empty media array despite successful 200 resp
-
Working on an application for WordPress (Progressive web app, hosted on Vercel) and the WordPress.com REST API
/rest/v1/sites/{site_id}/media/newendpoint consistently returns{"media": [], "errors": []}(empty media array) despite:– Correct OAuth scope permissions (
posts,media)
– Valid 200 HTTP response codes
– Proper FormData structure per documentation
– Correct file data and headers
– No CORs errors
– Posts are created as expected but not imagesThe application is intended to upload media to my account and create posts. This is a Premium account hosted on WordPress.com https://johneclark.wordpress.com
At this point, my questions are:
1. **Are there undocumented restrictions** on media uploads for certain account types or site configurations?
2. **Is the
posts,mediaOAuth scope sufficient** for the/rest/v1/sites/{site_id}/media/newendpoint?3. **Are there rate limiting or size restrictions** that return 200 but don’t process files?
4. **Should we be using a different endpoint** for WordPress.com hosted sites vs self-hosted WordPress?
5. **Are there required headers or request format specifics** not covered in the current documentation?
6. **Is there additional authentication or site setup** required beyond OAuth token with media scope?
—————————————————-
This is the TLDR with all the icky bicky details from the Markdown file I have been keeping:
# WordPress.com REST API Media Upload Bug Report
**Date:** September 20, 2025
**Reporter:** John E Clark
**Issue:** WordPress.com REST API v1 consistently returns empty media array despite successful 200 responses
## Issue Summary
The WordPress.com REST API
/rest/v1/sites/{site_id}/media/newendpoint consistently returns{"media": [], "errors": []}(empty media array) despite:– Correct OAuth scope permissions (
posts,media)– Valid 200 HTTP response codes
– Proper FormData structure per documentation
– Correct file data and headers
## Environment Details
– **API Endpoint:**
https://public-api.wordpress.com/rest/v1/sites/{site_id}/media/new– **Authentication:** OAuth 2.0 with
posts,mediascope– **Site ID:** 166975198 (verified accessible with provided token)
– **Platform:** Node.js serverless function (Vercel)
– **Client:** React web application
## Request Details
### OAuth Configuration
`javascript</p> <p>scope: ‘posts media'</p> <p>client_id: [VALID_CLIENT_ID]</p> <p>response_type: ‘token'</p> <p>`**Token Verification:** ✅ Token successfully grants access to site information and other API endpoints
### Request Format
`javascript</p> <p>// FormData structure</p> <p>const formData = new FormData();</p> <p>formData.append(‘media[]’, fileBuffer, filename);</p> <p>formData.append(‘attrs[0][caption]‘, caption);</p> <p>formData.append(‘attrs[0][alt]’, caption);</p> <p>// Request headers</p> <p>{</p> <p>’Authorization’: ‘BEARER [valid_token]’,</p> <p>’Content-Type’: ‘multipart/form-data; boundary=[auto-generated]'</p> <p>}</p> <p>`### File Details
– **File Type:** image/jpeg
– **File Size:** 486332 bytes (valid size, under limits)
– **Filename:** photo_1_1758071062577.jpg
– **MIME Type:** image/jpeg
– **File Data:** Valid JPEG buffer confirmed
## Expected vs Actual Behavior
### Expected Response
`json</p> <p>{</p> <p>”media”: [</p> <p>{</p> <p>”ID”: 12345,</p> <p>”URL”: “https://example.wordpress.com/wp-content/uploads/file.jpg”,</p> <p>”title”: “photo_1_1758071062577”,</p> <p>”caption”: “Photo caption”</p> <p>}</p> <p>],</p> <p>”errors”: []</p> <p>}</p> <p>`### Actual Response
`json</p> <p>{</p> <p>”media”: [],</p> <p>”errors”: []</p> <p>}</p> <p>`– **HTTP Status:** 200 OK ✅
– **Response Time:** ~80ms ✅
– **Media Array:** Empty ❌
– **Errors Array:** Empty (no error messages) ❌
## Troubleshooting Steps Attempted
### 1. OAuth Scope Verification
– ✅ **Tested:**
globalscope (too broad, requires additional permissions)– ✅ **Tested:**
posts,mediascope (correct for media uploads per documentation)– ✅ **Verified:** Token successfully authenticates and grants site access
### 2. Request Format Variations
– ✅ **Tested:**
media[]array format (per documentation)– ✅ **Tested:**
mediasingular format– ✅ **Tested:** Stream vs Buffer vs Blob data types
– ✅ **Tested:** Various FormData option structures
– ✅ **Tested:** With and without
attrsmetadata### 3. File Format Testing
– ✅ **Tested:** Multiple JPEG files (various sizes: 345KB – 486KB)
– ✅ **Tested:** Valid MIME types (
image/jpeg)– ✅ **Tested:** Proper file extensions (
.jpg)– ✅ **Tested:** Files under size limits (all < 10MB)
### 4. API Endpoint Verification
– ✅ **Tested:**
/rest/v1/sites/{site_id}/media/new(documented endpoint)– ✅ **Tested:**
/wp/v2/sites/{site_id}/media(returns 403, requiresglobalscope)– ✅ **Verified:** Site ID correctness via
/rest/v1/sites/{site_id}endpoint### 5. Request Structure Validation
`javascript</p> <p>// Tested approach based on WordPress REST API documentation</p> <p>formData.append(‘media[]’, fileBuffer, {</p> <p>filename: filename,</p> <p>contentType: ‘image/jpeg'</p> <p>});</p> <p>// Tested simplified approach based on community articles</p> <p>formData.append(‘media[]’, fileBuffer, filename);</p> <p>// Tested with various attribute formats</p> <p>formData.append(‘attrs[0][caption]‘, caption);</p> <p>formData.append(‘caption’, caption);</p> <p>`## Code Implementation
### Complete Working Example
`javascript</p> <p>export default async function handler(req, res) {</p> <p>try {</p> <p>// Parse multipart form data</p> <p>const form = formidable({ maxFileSize: 10 * 1024 * 1024 });</p> <p>const [fields, files] = await form.parse(req);</p> <p>const accessToken = fields.accessToken[0];</p> <p>const siteId = fields.siteId[0]; // “166975198”</p> <p>const filename = fields.filename[0];</p> <p>const caption = fields.caption[0];</p> <p>const mediaFile = files.media[0];</p> <p>const fileBuffer = fs.readFileSync(mediaFile.filepath);</p> <p>// FormData as per documentation</p> <p>const formData = new FormData();</p> <p>formData.append(‘media[]’, fileBuffer, filename);</p> <p>if (caption) {</p> <p>formData.append(‘attrs[0][caption]‘, caption);</p> <p>formData.append(‘attrs[0][alt]’, caption);</p> <p>}</p> <p>// API request</p> <p>const response = await fetch(</p> <p>https://public-api.wordpress.com/rest/v1/sites/${siteId}/media/new,</p> <p>{</p> <p>method: ‘POST’,</p> <p>headers: {</p> <p>’Authorization’:BEARER ${accessToken},</p> <p>…formData.getHeaders()</p> <p>},</p> <p>body: formData</p> <p>}</p> <p>);</p> <p>const result = await response.json();</p> <p>// result = {“media”: [], “errors”: []}</p> <p>} catch (error) {</p> <p>console.error(‘Upload failed:’, error);</p> <p>}</p> <p>}</p> <p>`## Diagnostic Information
### Network Logs
`</p> <p>POST https://public-api.wordpress.com/rest/v1/sites/166975198/media/new</p> <p>Status: 200 OK</p> <p>Response-Time: ~80ms</p> <p>Content-Type: application/json</p> <p>`### Request Headers
`</p> <p>Authorization: BEARER [valid_token]</p> <p>Content-Type: multipart/form-data; boundary=—-formdata-node-…</p> <p>Content-Length: [calculated]</p> <p>`### Response Headers
`</p> <p>HTTP/1.1 200 OK</p> <p>Content-Type: application/json</p> <p>Server: nginx</p> <p>`## Questions for WordPress Team
1. **Are there undocumented restrictions** on media uploads for certain account types or site configurations?
2. **Is the
posts,mediaOAuth scope sufficient** for the/rest/v1/sites/{site_id}/media/newendpoint?3. **Are there rate limiting or size restrictions** that return 200 but don’t process files?
4. **Should we be using a different endpoint** for WordPress.com hosted sites vs self-hosted WordPress?
5. **Are there required headers or request format specifics** not covered in the current documentation?
6. **Is there additional authentication or site setup** required beyond OAuth token with media scope?
## Impact
This issue prevents programmatic media uploads to WordPress.com sites, limiting integration capabilities for applications that need to:
– Upload user-generated content
– Create posts with embedded images
– Automate content publishing workflows
– Provide seamless WordPress publishing experiences
## Workaround
Currently implementing fallback simulation mode that generates WordPress-compatible post content without actual media uploads, allowing users to manually upload images later.
## Additional Context
– **Site Type:** Standard WordPress.com hosted site
– **Account Type:** [Please specify your account type]
– **Site URL:** https://johneclark.wordpress.com
– **API Documentation Referenced:** https://developer.wordpress.com/docs/api/1.1/post/sites/%24site/media/new/
## Request for Assistance
We would appreciate:
1. **Confirmation** if this is expected behavior or a bug
2. **Alternative approaches** if the current method is incorrect
3. **Additional debugging steps** to identify the root cause
4. **Timeline** for any potential fixes if this is a known issue
Thank you for your assistance in resolving this media upload issue.
The blog I need help with is: (visible only to logged in users)
- The topic ‘WordPress API media/new returns empty media array despite successful 200 resp’ is closed to new replies.