POST queued, running, and terminal events from Bitrise, Codemagic, GitHub Actions, Xcode Cloud, or any shell script. Retries update the same provider run instead of creating duplicates.
POST https://simpleappshipper.com/api/ci/build-completed Content-Type: application/json X-CI-Webhook-Token: <your shared secret> X-Device-ID: <device id from your Mac app> # legacy device-scoped flow Authorization: Bearer <sas_session_token> # signed-in flow # Supply Authorization or X-Device-ID. Linking a release workspace requires Authorization.
| Field | Type | Notes |
|---|---|---|
project | required | Repo name or Xcode project basename. Used to group builds. |
provider_run_id | required | Stable provider run identifier. The idempotency key is account/device + provider + project + this value. |
provider_event_id | optional | Provider event/delivery identifier retained for diagnostics. |
branch | optional | Git branch name. |
commit_sha | optional | Full or short SHA. Used for diffing in the Mac app. |
version_string | optional | e.g. "2.4.0". |
build_number | optional | e.g. "47". |
artifact_url | optional | HTTPS URL to the .ipa / .pkg / .app. R2, S3, GitHub artifact, etc. |
artifact_checksum_sha256 | optional | Exactly 64 hexadecimal characters. Returned as evidence; not fetched or verified server-side. |
artifact_kind | optional | ipa (default) · pkg · app |
platform | optional | ios (default) · macos · appletvos · visionos |
ci_provider | optional | bitrise · codemagic · github · xcode-cloud · manual · other |
ci_run_url | optional | Link back to the CI run for diagnostics. |
status | optional | queued · running · succeeded · failed · cancelled. Missing or legacy completed normalizes to succeeded; other values are rejected. |
queued_at, started_at, completed_at | optional | ISO-8601 lifecycle timestamps. A matching timestamp is filled when its event arrives without one. |
duration_seconds | optional | Non-negative integer, up to 31 days. Derived when start and completion timestamps are both present. |
tests | optional | Object with non-negative integer total, failed, and skipped counts. |
release_workspace_id | optional | Requires a valid JWT and owner, release manager, or editor membership in that workspace. |
metadata | optional | JSON object or array, bounded to 4 KB. Oversized metadata is discarded; secret, token, password, private-key, authorization, and command keys are rejected. |
200 OK
{
"id": "01HV9X…",
"accepted": true,
"idempotent": false
}
The authenticated list endpoint uses a strict integer limit from 1–100 and an opaque cursor returned by the preceding page. It returns lifecycle timestamps, duration, test totals, checksum, release workspace link, and bounded metadata.
GET https://simpleappshipper.com/api/ci/builds?project=MyApp&limit=20&cursor=<next_cursor>
Authorization: Bearer <sas_session_token>
200 OK
{
"builds": [
{
"provider_run_id": "run-42",
"status": "succeeded",
"duration_seconds": 120,
"tests": { "total": 20, "failed": 0, "skipped": 1 },
"artifact_checksum_sha256": "…"
}
],
"next_cursor": null
}
#!/usr/bin/env bash
curl -fsS https://simpleappshipper.com/api/ci/build-completed \
-H "Content-Type: application/json" \
-H "X-CI-Webhook-Token: $SAS_WEBHOOK_TOKEN" \
-H "X-Device-ID: $SAS_DEVICE_ID" \
-d "{
\"project\": \"$BITRISE_APP_TITLE\",
\"provider_run_id\": \"$BITRISE_BUILD_SLUG\",
\"provider_event_id\": \"$BITRISE_BUILD_SLUG-completed\",
\"status\": \"succeeded\",
\"branch\": \"$BITRISE_GIT_BRANCH\",
\"commit_sha\": \"$BITRISE_GIT_COMMIT\",
\"version_string\": \"$BITRISE_BUILD_VERSION\",
\"build_number\": \"$BITRISE_BUILD_NUMBER\",
\"artifact_url\": \"$BITRISE_PUBLIC_INSTALL_PAGE_URL\",
\"ci_provider\": \"bitrise\",
\"ci_run_url\": \"$BITRISE_BUILD_URL\"
}"
scripts:
- name: Notify Simple App Shipper
script: |
curl -fsS https://simpleappshipper.com/api/ci/build-completed \
-H "Content-Type: application/json" \
-H "X-CI-Webhook-Token: $SAS_WEBHOOK_TOKEN" \
-H "X-Device-ID: $SAS_DEVICE_ID" \
-d "{
\"project\": \"$CM_PROJECT_NAME\",
\"provider_run_id\": \"$CM_BUILD_ID\",
\"provider_event_id\": \"$CM_BUILD_ID-completed\",
\"status\": \"succeeded\",
\"branch\": \"$CM_BRANCH\",
\"commit_sha\": \"$CM_COMMIT\",
\"version_string\": \"$CM_BUILD_VERSION\",
\"build_number\": \"$CM_BUILD_NUMBER\",
\"ci_provider\": \"codemagic\",
\"ci_run_url\": \"$CM_BUILD_URL\"
}"
- name: Notify Simple App Shipper
if: success()
env:
SAS_WEBHOOK_TOKEN: ${{ '{{' }} secrets.SAS_WEBHOOK_TOKEN {{ '}}' }}
SAS_DEVICE_ID: ${{ '{{' }} secrets.SAS_DEVICE_ID {{ '}}' }}
run: |
curl -fsS https://simpleappshipper.com/api/ci/build-completed \
-H "Content-Type: application/json" \
-H "X-CI-Webhook-Token: $SAS_WEBHOOK_TOKEN" \
-H "X-Device-ID: $SAS_DEVICE_ID" \
-d "{
\"project\": \"${{ '{{' }} github.event.repository.name {{ '}}' }}\",
\"provider_run_id\": \"${{ '{{' }} github.run_id {{ '}}' }}-${{ '{{' }} github.run_attempt {{ '}}' }}\",
\"provider_event_id\": \"${{ '{{' }} github.run_id {{ '}}' }}-${{ '{{' }} github.run_attempt {{ '}}' }}-completed\",
\"status\": \"succeeded\",
\"branch\": \"${{ '{{' }} github.ref_name {{ '}}' }}\",
\"commit_sha\": \"${{ '{{' }} github.sha {{ '}}' }}\",
\"ci_provider\": \"github\",
\"ci_run_url\": \"${{ '{{' }} github.server_url {{ '}}' }}/${{ '{{' }} github.repository {{ '}}' }}/actions/runs/${{ '{{' }} github.run_id {{ '}}' }}\"
}"
Add a custom script under ci_post_xcodebuild.sh:
#!/usr/bin/env bash
curl -fsS https://simpleappshipper.com/api/ci/build-completed \
-H "Content-Type: application/json" \
-H "X-CI-Webhook-Token: $SAS_WEBHOOK_TOKEN" \
-H "X-Device-ID: $SAS_DEVICE_ID" \
-d "{
\"project\": \"$CI_PRODUCT\",
\"provider_run_id\": \"$CI_BUILD_ID\",
\"provider_event_id\": \"$CI_BUILD_ID-completed\",
\"status\": \"succeeded\",
\"branch\": \"$CI_BRANCH\",
\"commit_sha\": \"$CI_COMMIT\",
\"version_string\": \"$CI_BUILD_NUMBER\",
\"ci_provider\": \"xcode-cloud\",
\"ci_run_url\": \"$CI_BUILD_URL\"
}"
The webhook is a plain HTTPS POST. Any tool that can provide a stable provider_run_id and run curl can wire to it.
The CI Builds panel lists recent runs grouped by project, with provider, branch, version/build, commit, status, and links to the CI run or artifact when supplied. The ingestion service stores metadata only: it never downloads an artifact, starts an upload, invokes provider commands, or submits an app to App Store Connect.
CI_WEBHOOK_TOKEN is unset, empty, missing, or wrong, the Worker rejects the webhook. Every accepted event carries the matching X-CI-Webhook-Token.X-Device-ID header. A body-supplied user or device id is never trusted. Listing requires a signed-in account.release_workspace_id is accepted only for a signed-in owner, release manager, or editor member. Device-only calls, viewers, approvers, and non-members cannot link a run.