GitHub Actions: generate a release-note image with the Sume Images API
A workflow that fires when a release is published, calls Sume's image endpoint with curl and jq, downloads the result and uploads it as a build artifact.

To generate a release image from GitHub Actions, trigger on release: published, store your Sume key as a repository secret, call POST https://api.sume.com/v1/images with curl, pull data[0].url out with jq, download the file and upload it as an artifact. The whole job is about a dozen lines, and the only branch you must handle is the 202 that a slow image returns instead of the body.
Keep the model cheap for this job. A release card does not need a four-image batch at 4K, so send one image at the default size and a model whose list price you checked in GET /v1/images/models/{id}/endpoints.
What does each step do?
| Step | Purpose | Fails when |
|---|---|---|
| Trigger | release with type published | Never; it only runs on publish |
| Request | curl to /v1/images with the secret | 401 for a bad key, 400 for a rejected parameter |
| Parse | jq -r '.data[0].url' | The response was 202, so data has no image |
| Download | curl -L -o release.png | The URL is empty |
| Store | Upload artifact | The file does not exist |
What is the workflow?
Save it as .github/workflows/release-image.yml. The release name goes into the prompt through an environment variable, not by string-splicing it into the script.
name: release-image
on:
release:
types: [published]
jobs:
image:
runs-on: ubuntu-latest
env:
NAME: ${{ github.event.release.name }}
SUME_API_KEY: ${{ secrets.SUME_API_KEY }}
steps:
- name: Generate
run: |
body=$(jq -n --arg p "Clean abstract banner for a software release called $NAME" \
'{model:"bytedance-seed/seedream-4.5",prompt:$p,aspect_ratio:"16:9"}')
curl -sS https://api.sume.com/v1/images \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" -d "$body" -o resp.json
url=$(jq -er '.data[0].url' resp.json)
curl -sSL "$url" -o release.png
- uses: actions/upload-artifact@v4
with:
name: release-image
path: release.pngWhat about slow or failed generations?
jq -e makes the step fail when .data[0].url is missing, which covers both the 202 job envelope and an error body. Sume bills completed generations in full and does not bill failed ones, so a failed run costs nothing, but a rerun of a successful job generates and bills a new image. Do not wire the workflow to rerun automatically on failure without that in mind.
If you want the release image in the release itself, add a step that attaches release.png with the GitHub CLI after you have looked at it; unattended publishing of generated art is a choice to make deliberately.
Should the key be a secret or a variable?
A secret. The workflow above reads it through an environment variable on the job, so it is not printed unless you echo it, and the key should be one you can revoke without touching other systems. Use a key you create for this repository only.
Sources
Related posts
More in Integrations
- Sheets 20 million cells: how many Sume jobs can a ledger hold?
Google Sheets doubled its cell limit to 20 million. Work out how many Sume job rows fit by column count, and why GET /v1/jobs stays the system of record.
- Sheets manual calculation: keep paid Sume calls out of formulas
Google Sheets can now pause automatic recalculation. Keep Sume job submits in a menu-driven Apps Script, not formulas, so a recalc never buys a render.
- GPT-6.1 Sol is in ChatGPT Work and Codex, not chat: attach Sume's MCP
OpenAI put GPT-6.1 Sol in ChatGPT Work and Codex rather than regular chat. Which of those surfaces can take Sume's hosted MCP server.
- Hermes daily MCP re-auth nudge vs Sume's one-hour access token
Hermes Agent Desktop added a daily MCP re-auth nudge. Sume access tokens last 3600 seconds with no refresh token, so use an API key for scheduled work.
Written by Sume