Integration recipe

Publish a post with curl and the pixPLace API

Upload an image by URL and publish a post with two curl commands. Bearer key, Idempotency-Key, retries and the common errors explained.

Who it is for

Anyone who wants to try the API in a terminal first, or call it from a shell script or a cron job.

What it automates

Publish a post with an image: the server downloads the image from a public URL, then the post is created with the stored copy.

Steps

  1. Create an API key in Settings → Developer and export it as PIXPLACE_API_KEY. The full key is shown once.
  2. Call POST /api/v1/uploads/from-url with the public image URL. The answer holds data.publicUrl.
  3. Call POST /api/v1/posts with data.publicUrl as attachments[].url and its type as attachments[].type.
  4. Send an Idempotency-Key on both calls. If a call times out, repeat it with the same key: you get the original result, never a duplicate.
  5. When you create the key, tick the `publish` scope. A key without it gets 403 insufficient_scope on these calls.

Examples

Placeholders: ppk_live_XXXXXXXX is your key. The ids and the image address are samples. The API address is always https://pixplace.space/api/v1.

Step 1: upload the image by URL
curl -X POST https://pixplace.space/api/v1/uploads/from-url \
  -H "Authorization: Bearer ppk_live_XXXXXXXX" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: upload-0001" \
  -d '{
  "url": "https://example.com/photos/living-room.jpg"
}'
Step 2: create the post with data.publicUrl
curl -X POST https://pixplace.space/api/v1/posts \
  -H "Authorization: Bearer ppk_live_XXXXXXXX" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: post-0001" \
  -d '{
  "title": "Minimalist living room",
  "attachments": [
    {
      "url": "https://cdn.pixplace.space/content/cm00000000000000000000001/2026-10/00000000-0000-4000-8000-000000000004.jpg",
      "type": "IMAGE"
    }
  ],
  "description": "AI-generated interior concept"
}'
Read the answer with jq
# the post address is in data.url of the step 2 answer
curl -s -X POST ... | jq -r .data.url

Common errors

StatusCauseWhat to do
400The body is invalid: a missing title, a media URL that is not https, or a type other than IMAGE or VIDEO. The message names the field.Fix the field named in the error message. Nothing was written and no quota was spent, so do not retry the same body.
401The API key is missing, malformed, revoked or sent in the wrong header.In curl the key goes into -H "Authorization: Bearer ...", not into the URL. The header must read Authorization: Bearer followed by your ppk_live_ key. Check the key in Settings → Developer.
403The key lacks a scope the call needs: the answer is 403 with error.code insufficient_scope and the missing scope in error.required.Create a new key in Settings → Developer with the `publish` scope ticked and use it instead; repeating the call with the same key fails the same way.
429A per-minute or per-day limit was reached. The Retry-After header and the retryAfter field of the body say how many seconds to wait.Wait that long and repeat with the SAME Idempotency-Key. In a script, read the Retry-After header with curl -i and sleep that many seconds.
502The server could not download the source URL: it answered 4xx or 5xx, the host does not resolve or the response was compressed.Open the source URL in a private browser window. It must be public and answer 200 without a login.

The full list of statuses, the retry rules and the limits are in Errors and retries.

Other tools