GitHub Actions Upload Artifact to Public URL with cURL

June 25, 2026 · 6 min read

GitHub Actions artifacts are good for storing files from a workflow run. They are not always the right shape when you need a public URL for a customer, a stakeholder, a webhook, or an external system.

If your workflow produces an HTML report, PDF, screenshot, ZIP, or release file and you need a direct public link, upload it to FilePost with cURL during the workflow.

Why Not Just Use GitHub Artifacts?

GitHub's artifact system is built for workflow storage and sharing between jobs. GitHub documents artifact retention and configurable retention periods for workflow artifacts. That is useful, but it is not the same as a permanent public CDN URL.

Use GitHub artifacts for developer workflow storage. Use FilePost when another system needs a normal HTTPS link.

Official reference: GitHub docs: store and share data with workflow artifacts.

Step 1: Add Your API Key as a Secret

In your repository settings, add a secret named FILEPOST_API_KEY. Never hardcode the key in the workflow file.

Step 2: Upload the File

This example uploads an HTML report and writes the resulting URL to the GitHub step summary.

name: Upload report

on:
  workflow_dispatch:

jobs:
  report:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build report
        run: |
          mkdir -p dist
          echo "<h1>CI report</h1>" > dist/report.html

      - name: Upload report to FilePost
        env:
          FILEPOST_API_KEY: ${{ secrets.FILEPOST_API_KEY }}
        run: |
          URL=$(curl -sS -X POST https://filepost.dev/v1/upload \
            -H "X-API-Key: $FILEPOST_API_KEY" \
            -F "file=@dist/report.html" | jq -r '.url')

          echo "REPORT_URL=$URL" >> "$GITHUB_ENV"
          echo "### Public report URL" >> "$GITHUB_STEP_SUMMARY"
          echo "$URL" >> "$GITHUB_STEP_SUMMARY"

Step 3: Use the URL Later in the Workflow

After the upload step, later steps can read $REPORT_URL. For example, send it to a webhook:

- name: Notify external system
  run: |
    curl -sS -X POST https://example.com/webhook \
      -H "Content-Type: application/json" \
      -d "{\"report_url\":\"$REPORT_URL\"}"

Upload a ZIP Build Output

- name: Zip build output
  run: zip -r build.zip dist/

- name: Upload ZIP to FilePost
  env:
    FILEPOST_API_KEY: ${{ secrets.FILEPOST_API_KEY }}
  run: |
    curl -sS -X POST https://filepost.dev/v1/upload \
      -H "X-API-Key: $FILEPOST_API_KEY" \
      -F "file=@build.zip"

Upload a Temporary Preview

If the URL should expire, use the base64 endpoint only when your file is already a string. For a normal file on disk, keep using multipart. FilePost supports expiration on upload flows that include expires_in; use it for generated previews that should disappear later.

Good CI Use Cases

Troubleshooting

jq: command not found

GitHub's Ubuntu runners normally include jq, but if your runner does not, install it or use a small Node/Python parser. The upload still works; parsing the URL is the only part that needs jq.

401 invalid API key

Check that the secret name is exactly FILEPOST_API_KEY and that the workflow has access to repository secrets. For pull requests from forks, GitHub restricts secrets by design.

413 file too large

Check your FilePost plan limit. Free supports 50 MB, Starter supports 200 MB, and Pro supports 500 MB per file.

Upload CI files to a public CDN URL

Use one cURL command in GitHub Actions and share reports, screenshots, and build files outside GitHub.

Get Your API Key