Integration recipe

Publish to pixPLace on a schedule with GitHub Actions

A scheduled GitHub Actions workflow uploads an image by URL and publishes a post, with the API key stored in repository secrets.

Who it is for

Developers and teams who already keep content or a release process in a GitHub repository.

What it automates

Publish a post on a schedule or after a release: upload the image by URL, then create the post.

Steps

  1. In the repository open Settings, Secrets and variables, Actions, and add a secret named PIXPLACE_API_KEY with your key.
  2. Add the workflow file below as .github/workflows/pixplace.yml. The key is read from secrets.PIXPLACE_API_KEY and never written into the file.
  3. The first step uploads the image and passes data.publicUrl on as a step output. The second step creates the post.
  4. The Idempotency-Key uses github.run_id. Re-running a failed run therefore returns the original post instead of a second one.
  5. When you create the key, tick the `publish` scope. A key without it gets 403 insufficient_scope on these calls.

Example

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.

.github/workflows/pixplace.yml
name: Publish a post
on:
  schedule:
    - cron: "0 9 * * 1"
  workflow_dispatch:
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - name: Upload the image
        id: upload
        env:
          PIXPLACE_API_KEY: ${{ secrets.PIXPLACE_API_KEY }}
        run: |
          curl --fail-with-body -sS -X POST https://pixplace.space/api/v1/uploads/from-url \
            -H "Authorization: Bearer ${PIXPLACE_API_KEY}" \
            -H "Content-Type: application/json" \
            -H "Idempotency-Key: upload-${{ github.run_id }}" \
            -d '{"url": "https://example.com/photos/living-room.jpg"}' > upload.json
          echo "url=$(jq -r .data.publicUrl upload.json)" >> "$GITHUB_OUTPUT"
      - name: Create the post
        env:
          PIXPLACE_API_KEY: ${{ secrets.PIXPLACE_API_KEY }}
          PUBLIC_URL: ${{ steps.upload.outputs.url }}
        run: |
          jq -n --arg url "$PUBLIC_URL" '{title: "Minimalist living room", attachments: [{url: $url, type: "IMAGE"}]}' > post.json
          curl --fail-with-body -sS -X POST https://pixplace.space/api/v1/posts \
            -H "Authorization: Bearer ${PIXPLACE_API_KEY}" \
            -H "Content-Type: application/json" \
            -H "Idempotency-Key: post-${{ github.run_id }}" \
            -d @post.json

Common errors

StatusCauseWhat to do
400post.json has an empty title or an empty url, because the upload step failed or its output is empty.Open the log of the upload step. curl --fail-with-body prints the error body, which names the field.
401The API key is missing, malformed, revoked or sent in the wrong header.The secret is missing or misspelled, so the header is empty. Secrets are not passed to workflows that run from a fork. 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. The job fails with the error body. Re-run the failed job later: the run id is the same, so the Idempotency-Key is the same.
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