# Create a webhook endpoint

- **OpenAPI Version:** `3.2.0`
- **API Version:** `3.1.0`
- **Contact:** Syndai <https://syndai.ai>

## Contents

**Operations**

- [POST /api/v1/external/coding/webhooks](#scalar-operation-post-apiv1externalcodingwebhooks)

**Schemas**

- [WebhookEndpointCreateRequest](#scalar-schema-webhookendpointcreaterequest)
- [CodingWebhookEventType](#scalar-schema-codingwebhookeventtype)
- [WebhookEndpointCreateResponse](#scalar-schema-webhookendpointcreateresponse)
- [WebhookEndpointRead](#scalar-schema-webhookendpointread)
- [WebhookEndpointStatus](#scalar-schema-webhookendpointstatus)
- [ProblemDetail](#scalar-schema-problemdetail)
- [ExternalErrorCode](#scalar-schema-externalerrorcode)

<a id="scalar-context-global-servers"></a>

## Servers

- **URL:** `https://api.syndai.ai`

<a id="scalar-context-global-authentication"></a>

## Authentication

- **CustomerApiKey**: HTTP bearer (`API Key`)

  Customer API key sent as a bearer token

## Tags

### Webhooks

Signed HTTP callbacks for run events. Register endpoints, send a test event, rotate the signing secret, and list or redeliver past deliveries. Verify every delivery's signature and treat events as at-least-once.

## Operations

<a id="scalar-operation-post-apiv1externalcodingwebhooks"></a>

### Create a webhook endpoint

- **Method:** `POST`
- **Path:** `/api/v1/external/coding/webhooks`
- **Operation ID:** `createWebhookEndpoint`
- **Tags:** Webhooks

Register a webhook endpoint to receive deliveries for your runs. The response carries the endpoint's signing secret exactly once: store it then, it is never returned again. Requires the `coding:webhooks:write` scope.

**Servers:** [Inherited servers](#scalar-context-global-servers)

**Authentication:** [Global authentication](#scalar-context-global-authentication)

#### Query parameters

- **`customer_id`**: `string | null`, format: `uuid`

#### Request body

**Required:** `true`

**Content type:** `application/json`

[WebhookEndpointCreateRequest](#scalar-schema-webhookendpointcreaterequest)

**Example:**

```json
{
  "event_types": [
    "coding.run.completed",
    "coding.run.failed"
  ],
  "name": "Ops alerts",
  "target_url": "https://hooks.example.com/syndai"
}
```

#### Responses

##### 201 Document created, URL follows

**Content type:** `application/json`

[WebhookEndpointCreateResponse](#scalar-schema-webhookendpointcreateresponse)

**Example:**

```json
{
  "endpoint": {
    "created_at": "2026-10-27T09:00:00Z",
    "customer_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
    "event_types": [
      "coding.run.completed",
      "coding.run.failed"
    ],
    "id": "9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
    "name": "Ops alerts",
    "status": "active",
    "target_url": "https://hooks.example.com/syndai",
    "updated_at": "2026-10-27T09:00:00Z"
  },
  "signing_secret": "example-signing-secret-shown-once"
}
```

##### 400, 401, 403, 404

- `400` Bad request syntax or unsupported method
- `401` Invalid or missing customer API key
- `403` Insufficient scope or forbidden customer access
- `404` Resource not found

**Content type:** `application/problem+json`

[ProblemDetail](#scalar-schema-problemdetail)

RFC 7807 problem detail returned for public CaaS errors.

<a id="scalar-example-1"></a>

**Generated example:**

```json
{
  "code": "BUDGET_EXHAUSTED",
  "detail": null,
  "existing_run_id": null,
  "instance": null,
  "status": 1,
  "title": "",
  "type": "about:blank",
  "additionalProperty": "anything"
}
```

##### 429 Rate limit exceeded

**Headers:**

- **`Retry-After`**

  Seconds to wait before retrying the request

  `integer`

**Content type:** `application/problem+json`

[ProblemDetail](#scalar-schema-problemdetail)

RFC 7807 problem detail returned for public CaaS errors.

[Generated example](#scalar-example-1)

##### default Unexpected error

**Content type:** `application/problem+json`

[ProblemDetail](#scalar-schema-problemdetail)

<a id="scalar-example-2"></a>

**Generated example:**

```json
null
```

## Schemas

<a id="scalar-schema-webhookendpointcreaterequest"></a>

### WebhookEndpointCreateRequest

**Type:** `object`

- **`name` (required)**: `string`
- **`target_url` (required)**: `string`
- **`event_types`**: `array`

  **Items:**

  `string`, possible values: `"coding.webhook.test", "coding.run.created", "coding.run.phase_changed", "coding.run.route_changed", "coding.run.question_required", "coding.run.liveness_changed", "coding.execution.attempt.started", "coding.execution.attempt.completed", "coding.validation.completed", "coding.review_gate.completed", "coding.artifact.created", "coding.pr.opened", "coding.pr.merged", "coding.run.completed", "coding.run.failed", "coding.run.cancelled", "coding.run.delivery_marked", "coding.run.ac_contested", "coding.run.final_response_ready", "coding.run.final_response_failed", "coding.run.capability.started", "coding.run.capability.finished", "coding.run.capability.governance_required", "coding.run.preview_ready", "coding.run.steer_received", "coding.run.steer_applied", "coding.run.steer_orphaned", "coding.run.spec_review_ready", "coding.run.loop_breaker_fired", "coding.run.notice", "coding.run.land_changed"`

  External webhook and SSE event taxonomy for Coding-as-a-Service.

**Example:**

```json
{
  "event_types": [
    "coding.run.completed",
    "coding.run.failed"
  ],
  "name": "Ops alerts",
  "target_url": "https://hooks.example.com/syndai"
}
```

<a id="scalar-schema-codingwebhookeventtype"></a>

### CodingWebhookEventType

**Type:** `string`, possible values: `"coding.webhook.test", "coding.run.created", "coding.run.phase_changed", "coding.run.route_changed", "coding.run.question_required", "coding.run.liveness_changed", "coding.execution.attempt.started", "coding.execution.attempt.completed", "coding.validation.completed", "coding.review_gate.completed", "coding.artifact.created", "coding.pr.opened", "coding.pr.merged", "coding.run.completed", "coding.run.failed", "coding.run.cancelled", "coding.run.delivery_marked", "coding.run.ac_contested", "coding.run.final_response_ready", "coding.run.final_response_failed", "coding.run.capability.started", "coding.run.capability.finished", "coding.run.capability.governance_required", "coding.run.preview_ready", "coding.run.steer_received", "coding.run.steer_applied", "coding.run.steer_orphaned", "coding.run.spec_review_ready", "coding.run.loop_breaker_fired", "coding.run.notice", "coding.run.land_changed"`

External webhook and SSE event taxonomy for Coding-as-a-Service.

<a id="scalar-schema-webhookendpointcreateresponse"></a>

### WebhookEndpointCreateResponse

**Type:** `object`

- **`endpoint` (required)**: [WebhookEndpointRead](#scalar-schema-webhookendpointread)
- **`signing_secret` (required)**: `string`, format: `password`

**Example:**

```json
{
  "endpoint": {
    "created_at": "2026-10-27T09:00:00Z",
    "customer_id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
    "event_types": [
      "coding.run.completed",
      "coding.run.failed"
    ],
    "id": "9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
    "name": "Ops alerts",
    "status": "active",
    "target_url": "https://hooks.example.com/syndai",
    "updated_at": "2026-10-27T09:00:00Z"
  },
  "signing_secret": "example-signing-secret-shown-once"
}
```

<a id="scalar-schema-webhookendpointread"></a>

### WebhookEndpointRead

**Type:** `object`

- **`created_at` (required)**: `string`, format: `date-time`
- **`customer_id` (required)**: `string`, format: `uuid`
- **`event_types` (required)**: `array of string`
- **`id` (required)**: `string`, format: `uuid`
- **`name` (required)**: `string`
- **`status` (required)**: `string`, possible values: `"active", "disabled", "revoked"`

  Lifecycle state for customer-managed webhook endpoints.
- **`target_url` (required)**: `string`
- **`updated_at` (required)**: `string`, format: `date-time`
- **`last_secret_rotated_at`**: `string | null`, format: `date-time`

<a id="scalar-example-3"></a>

**Generated example:**

```json
{
  "created_at": "",
  "customer_id": "",
  "event_types": [
    ""
  ],
  "id": "",
  "last_secret_rotated_at": "",
  "name": "",
  "status": "active",
  "target_url": "",
  "updated_at": ""
}
```

<a id="scalar-schema-webhookendpointstatus"></a>

### WebhookEndpointStatus

**Type:** `string`, possible values: `"active", "disabled", "revoked"`

Lifecycle state for customer-managed webhook endpoints.

<a id="scalar-schema-problemdetail"></a>

### ProblemDetail

**Type:** `object`

RFC 7807 problem detail returned for public CaaS errors.

- **`code` (required)**: `string`, possible values: `"BUDGET_EXHAUSTED", "QUOTA_EXCEEDED", "RUN_CONCURRENCY_LIMIT", "CUSTOMER_DISABLED", "REPO_NOT_BOUND", "IDEMPOTENCY_REPLAY", "CONFLICT", "MISSION_BUSY_RETRY", "HITL_REQUEST_CONFLICT", "HITL_REQUEST_SETTLED", "RUN_TERMINATED_BEFORE_RESPONSE", "INVALID_POLICY", "INVALID_SCOPE", "RATE_LIMITED", "INSTALLATION_INCOMPLETE", "SUBSCRIPTION_USAGE_UNAVAILABLE", "INVALID_TOKEN", "ROLE_REQUIRED", "PLAN_UPGRADE_REQUIRED", "EMAIL_MISMATCH", "EXPIRED_TOKEN", "NOT_FOUND", "OVERSCOPE_ACK_REQUIRED", "VERIFY_FAILED", "PUBLISH_IN_FLIGHT", "PUBLISH_UNSUPPORTED_REPO", "PUBLICATION_NOT_LIVE", "NO_APP_DATA", "FEATURE_REQUESTS_NEEDS_MEMBERS", "EMPTY_UPDATE", "BAD_CURSOR", "HUMAN_APPROVAL_REQUIRED", "PROTECTED_PATHS_MANAGED_ONLY", "RUN_IN_FLIGHT", "TEXT_EDIT_REFUSED", "CLI_UPGRADE_REQUIRED", "PRODUCTION_STEP_UP_REQUIRED", "PRICES_UPDATING", "GITHUB_UNAVAILABLE", "PUBLISH_NOT_SET_UP", "VERSION_NOT_DEPLOYED", "INTERNAL_ERROR"`

  Stable error codes surfaced to public CaaS clients.
- **`status` (required)**: `integer`
- **`title` (required)**: `string`
- **`detail`**: `string | null`, default: `null`
- **`existing_run_id`**: `string | null`, default: `null`
- **`instance`**: `string | null`, default: `null`
- **`type`**: `string`, default: `"about:blank"`

<a id="scalar-example-4"></a>

**Generated example:**

```json
{
  "code": "BUDGET_EXHAUSTED",
  "detail": null,
  "existing_run_id": null,
  "instance": null,
  "status": 1,
  "title": "",
  "type": "about:blank",
  "additionalProperty": "anything"
}
```

<a id="scalar-schema-externalerrorcode"></a>

### ExternalErrorCode

**Type:** `string`, possible values: `"BUDGET_EXHAUSTED", "QUOTA_EXCEEDED", "RUN_CONCURRENCY_LIMIT", "CUSTOMER_DISABLED", "REPO_NOT_BOUND", "IDEMPOTENCY_REPLAY", "CONFLICT", "MISSION_BUSY_RETRY", "HITL_REQUEST_CONFLICT", "HITL_REQUEST_SETTLED", "RUN_TERMINATED_BEFORE_RESPONSE", "INVALID_POLICY", "INVALID_SCOPE", "RATE_LIMITED", "INSTALLATION_INCOMPLETE", "SUBSCRIPTION_USAGE_UNAVAILABLE", "INVALID_TOKEN", "ROLE_REQUIRED", "PLAN_UPGRADE_REQUIRED", "EMAIL_MISMATCH", "EXPIRED_TOKEN", "NOT_FOUND", "OVERSCOPE_ACK_REQUIRED", "VERIFY_FAILED", "PUBLISH_IN_FLIGHT", "PUBLISH_UNSUPPORTED_REPO", "PUBLICATION_NOT_LIVE", "NO_APP_DATA", "FEATURE_REQUESTS_NEEDS_MEMBERS", "EMPTY_UPDATE", "BAD_CURSOR", "HUMAN_APPROVAL_REQUIRED", "PROTECTED_PATHS_MANAGED_ONLY", "RUN_IN_FLIGHT", "TEXT_EDIT_REFUSED", "CLI_UPGRADE_REQUIRED", "PRODUCTION_STEP_UP_REQUIRED", "PRICES_UPDATING", "GITHUB_UNAVAILABLE", "PUBLISH_NOT_SET_UP", "VERSION_NOT_DEPLOYED", "INTERNAL_ERROR"`

Stable error codes surfaced to public CaaS clients.
