API / handle-origin-installation-webhooks

API

Handle Origin installation webhooks

Origin always delivers the five installation.* events to the app itself. They do not appear in the app's selectable webhook events list. Official reference: llms-full.txt → Events. OpenAPI schemas: InstallationCreatedWebhookPayload, InstallationUpdatedWebhookPayload, InstallationSuspendedWebhookPayload, InstallationUnsuspendedWebhookPayload, InstallationDeletedWebhookPayload.

Origin is in Early Beta and subject to change. Delivery uses the same signed envelope as other Origin webhooks.

Events

event.type When it fires
installation.created The app is installed on a namespace.
installation.updated Scopes, repository selection, or the owner namespace slug change.
installation.suspended The installation is suspended.
installation.unsuspended A suspended installation is restored.
installation.deleted The app is uninstalled.

Shared payload fields

Field Meaning
installation Snapshot matching Get App Installation field names
installation.id Installation id (inst_…)
installation.appId Same value as app.id
installation.target Owner namespace (slug, id, type)
installation.repoSelectionMode How repositories are selected
installation.repositories Selected repository references (may include mirrors)
installation.scopes Granted scopes
installation.repositoriesCount Count of selected repositories
installation.installedBy User who installed (or last re-consented); may be omitted if the user record is unreadable
installation.createdAt / installation.updatedAt Timestamps (updatedAt on created/updated)
installation.suspendedAt Set while suspended; omitted while active
installation.deletedAt Present on installation.deleted snapshots
app id and optional displayName

Sample installation.created event.payload:

{
  "installation": {
    "id": "inst_01k2ja2000e0080000000000b2",
    "appId": "app_01k2ja2000e0080000000000a1",
    "target": {
      "slug": "acme",
      "id": "ns_01k2ja2000e0080000000000p3",
      "type": "team"
    },
    "repoSelectionMode": "selected",
    "repositories": [
      {
        "id": "repo_01k2ja2000e0080000000000q4",
        "name": "rocket",
        "owner": {
          "slug": "acme",
          "id": "ns_01k2ja2000e0080000000000p3",
          "type": "team"
        }
      }
    ],
    "scopes": [
      "repository:contents:read",
      "repository:pull_requests:read"
    ],
    "repositoriesCount": 1,
    "createdAt": "2026-08-01T09:30:00Z",
    "updatedAt": "2026-08-01T09:30:00Z",
    "installedBy": {
      "id": "user_01k2ja2000e0080000000000c3",
      "email": "jane@acme.dev"
    }
  },
  "app": {
    "id": "app_01k2ja2000e0080000000000a1",
    "displayName": "CI Status Bot"
  }
}

Receiver tips

  1. Verify the signature, then branch on event.type.
  2. On created / updated, persist installation.id, target, scopes, and the repository list before minting installation access tokens.
  3. On suspended, stop scheduling work that needs that installation; on unsuspended, resume.
  4. On deleted, drop stored tokens for that installation — Origin invalidates them before expiresAt.
  5. Mirrored repositories may appear in the selected arrays; delivery does not widen what the installation can call on those mirrors.

Pitfalls

  • Do not expect to toggle these five events in Create App / Update App events — Origin always sends them.
  • Treat selected repository arrays as the set your app can reach, then still honor mirror read-only rules on the REST and Git surfaces.
  • Keep the receiver answering within the 10-second delivery deadline.