{
  "openapi": "3.1.0",
  "info": {
    "title": "Catchook API",
    "version": "0.1.0",
    "description": "API core de Catchook — gestion de webhooks"
  },
  "components": {
    "schemas": {
      "Project": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "org_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "created_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "name",
          "slug",
          "created_at"
        ]
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          },
          "timestamp": {
            "type": "string"
          }
        },
        "required": [
          "error",
          "timestamp"
        ]
      },
      "Endpoint": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "project_id": {
            "type": "string"
          },
          "org_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "provider": {
            "type": "string",
            "enum": [
              "stripe",
              "github",
              "shopify",
              "twilio",
              "linear",
              "custom"
            ]
          },
          "verification_method": {
            "type": "string",
            "enum": [
              "hmac_sha256",
              "hmac_sha1",
              "twilio_signature",
              "bearer_token",
              "basic_auth",
              "jwt",
              "ip_allowlist",
              "none"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "disabled"
            ]
          },
          "url": {
            "type": "string"
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "deleted_at": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "id",
          "project_id",
          "org_id",
          "name",
          "provider",
          "verification_method",
          "status",
          "url",
          "created_at",
          "updated_at",
          "deleted_at"
        ]
      },
      "TestEndpointResult": {
        "type": "object",
        "properties": {
          "accepted": {
            "type": "boolean",
            "description": "Whether the ingest endpoint accepted it."
          },
          "status": {
            "type": "number",
            "description": "The HTTP status the ingest endpoint answered."
          },
          "event_id": {
            "type": "string",
            "nullable": true,
            "description": "The recorded event, when it was accepted."
          },
          "error": {
            "type": "string",
            "nullable": true,
            "description": "Why it was not accepted, in the words the ingest service itself used — for example: missing header x-signature, or signature mismatch."
          },
          "url": {
            "type": "string",
            "description": "The ingest URL the test was sent to."
          }
        },
        "required": [
          "accepted",
          "status",
          "event_id",
          "error",
          "url"
        ]
      },
      "EndpointWithSecret": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Endpoint"
          },
          {
            "type": "object",
            "properties": {
              "verification_config": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "secret": {
                        "type": "string",
                        "minLength": 1
                      },
                      "header": {
                        "type": "string",
                        "minLength": 1
                      },
                      "prefix": {
                        "type": "string",
                        "description": "Which entry of a Stripe-style CSV header holds the digest, e.g. \"v1\""
                      },
                      "encoding": {
                        "type": "string",
                        "enum": [
                          "hex",
                          "base64"
                        ],
                        "description": "How the provider encodes the digest — hex unless stated otherwise (Shopify: base64)"
                      }
                    },
                    "required": [
                      "secret",
                      "header"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "properties": {
                      "token": {
                        "type": "string",
                        "minLength": 1
                      }
                    },
                    "required": [
                      "token"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "properties": {
                      "username": {
                        "type": "string",
                        "minLength": 1
                      },
                      "password": {
                        "type": "string",
                        "minLength": 1
                      }
                    },
                    "required": [
                      "username",
                      "password"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "properties": {
                      "jwks_url": {
                        "type": "string",
                        "minLength": 1
                      },
                      "audience": {
                        "type": "string"
                      },
                      "issuer": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "jwks_url"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "properties": {
                      "auth_token": {
                        "type": "string",
                        "minLength": 1
                      }
                    },
                    "required": [
                      "auth_token"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "properties": {
                      "ips": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1
                        },
                        "minItems": 1,
                        "description": "Literal addresses or IPv4 CIDR blocks — providers publish ranges",
                        "example": [
                          "13.110.0.0/16",
                          "54.187.174.169"
                        ]
                      }
                    },
                    "required": [
                      "ips"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "properties": {},
                    "additionalProperties": false
                  }
                ]
              }
            },
            "required": [
              "verification_config"
            ]
          }
        ]
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "project_id": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "prefix": {
            "type": "string",
            "nullable": true
          },
          "start": {
            "type": "string",
            "nullable": true
          },
          "enabled": {
            "type": "boolean"
          },
          "expires_at": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "project_id",
          "name",
          "prefix",
          "start",
          "enabled",
          "expires_at",
          "created_at",
          "updated_at"
        ]
      },
      "ApiKeyCreated": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ApiKey"
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "description": "The key in clear text — shown only here, at creation"
              }
            },
            "required": [
              "key"
            ]
          }
        ]
      },
      "Destination": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "endpoint_id": {
            "type": "string"
          },
          "org_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "receiver_url": {
            "type": "string"
          },
          "forward_original_signature": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "disabled"
            ]
          },
          "retry_max_attempts": {
            "type": "number"
          },
          "retry_backoff": {
            "type": "string",
            "enum": [
              "exponential",
              "linear",
              "fixed"
            ]
          },
          "rate_limit_max": {
            "type": "number",
            "nullable": true
          },
          "rate_limit_window": {
            "type": "string",
            "nullable": true,
            "enum": [
              "second",
              "minute",
              "hour",
              "day",
              null
            ]
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "deleted_at": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "id",
          "endpoint_id",
          "org_id",
          "name",
          "receiver_url",
          "forward_original_signature",
          "status",
          "retry_max_attempts",
          "retry_backoff",
          "rate_limit_max",
          "rate_limit_window",
          "created_at",
          "updated_at",
          "deleted_at"
        ]
      },
      "DestinationWithSecret": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Destination"
          },
          {
            "type": "object",
            "properties": {
              "catchook_secret": {
                "type": "string",
                "description": "HMAC secret Catchook uses to sign deliveries to this destination"
              }
            },
            "required": [
              "catchook_secret"
            ]
          }
        ]
      },
      "Event": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "evt_5f2b1c4a9e3d4f1a8b6c7d8e9f0a1b2c"
          },
          "endpoint_id": {
            "type": "string"
          },
          "org_id": {
            "type": "string"
          },
          "provider": {
            "type": "string",
            "enum": [
              "stripe",
              "github",
              "shopify",
              "twilio",
              "linear",
              "custom"
            ]
          },
          "received_at": {
            "type": "string"
          },
          "signature_valid": {
            "type": "boolean"
          },
          "verification_error": {
            "type": "string",
            "nullable": true,
            "description": "Why this event was not accepted, when it was not. Null on success. Actionable on purpose: \"verification config is missing \\\"token\\\"\", \"IP 203.0.113.7 is not allowlisted\", \"endpoint is paused\".",
            "example": "signature mismatch"
          },
          "payload_size_bytes": {
            "type": "number"
          },
          "delivery_summary": {
            "$ref": "#/components/schemas/EventDeliverySummary"
          }
        },
        "required": [
          "id",
          "endpoint_id",
          "org_id",
          "provider",
          "received_at",
          "signature_valid",
          "verification_error",
          "payload_size_bytes"
        ]
      },
      "EventDeliverySummary": {
        "type": "object",
        "nullable": true,
        "properties": {
          "delivered": {
            "type": "number"
          },
          "failed": {
            "type": "number"
          },
          "pending": {
            "type": "number"
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "delivered",
          "failed",
          "pending",
          "total"
        ]
      },
      "EventFacets": {
        "type": "object",
        "properties": {
          "total_events": {
            "type": "number"
          },
          "by_provider": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "value": {
                  "type": "string"
                },
                "count": {
                  "type": "number"
                }
              },
              "required": [
                "value",
                "count"
              ]
            }
          },
          "by_signature_valid": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "value": {
                  "type": "boolean"
                },
                "count": {
                  "type": "number"
                }
              },
              "required": [
                "value",
                "count"
              ]
            }
          },
          "by_attempt_status": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "value": {
                  "type": "string",
                  "enum": [
                    "delivered",
                    "failed",
                    "rate_limited",
                    "timeout",
                    "dead"
                  ]
                },
                "count": {
                  "type": "number"
                }
              },
              "required": [
                "value",
                "count"
              ]
            }
          }
        },
        "required": [
          "total_events",
          "by_provider",
          "by_signature_valid",
          "by_attempt_status"
        ]
      },
      "EventDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Event"
          },
          {
            "type": "object",
            "properties": {
              "headers": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              },
              "payload": {
                "nullable": true
              },
              "raw_payload": {
                "type": "string"
              },
              "attempts": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DeliveryAttempt"
                }
              }
            },
            "required": [
              "headers",
              "raw_payload",
              "attempts"
            ]
          }
        ]
      },
      "DeliveryAttempt": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "att_5f2b1c4a9e3d4f1a8b6c7d8e9f0a1b2c"
          },
          "event_id": {
            "type": "string"
          },
          "destination_id": {
            "type": "string"
          },
          "endpoint_id": {
            "type": "string"
          },
          "org_id": {
            "type": "string"
          },
          "attempted_at": {
            "type": "string"
          },
          "attempt_number": {
            "type": "number"
          },
          "receiver_url": {
            "type": "string"
          },
          "http_status": {
            "type": "number"
          },
          "response_body": {
            "type": "string"
          },
          "latency_ms": {
            "type": "number"
          },
          "status": {
            "type": "string",
            "enum": [
              "delivered",
              "failed",
              "rate_limited",
              "timeout",
              "dead"
            ]
          },
          "next_retry_at": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "id",
          "event_id",
          "destination_id",
          "endpoint_id",
          "org_id",
          "attempted_at",
          "attempt_number",
          "receiver_url",
          "http_status",
          "response_body",
          "latency_ms",
          "status",
          "next_retry_at"
        ]
      },
      "ReplayResult": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "string"
          },
          "enqueued": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "destination_id": {
                  "type": "string"
                }
              },
              "required": [
                "destination_id"
              ]
            }
          }
        },
        "required": [
          "event_id",
          "enqueued"
        ]
      },
      "ReplayDestinationResult": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "string"
          },
          "destination_id": {
            "type": "string"
          }
        },
        "required": [
          "event_id",
          "destination_id"
        ]
      }
    },
    "parameters": {}
  },
  "paths": {
    "/projects": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "List projects for the current organization",
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "required": false,
            "name": "page",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "List of projects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Project"
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "page": {
                          "type": "number"
                        },
                        "limit": {
                          "type": "number"
                        },
                        "total": {
                          "type": "number"
                        },
                        "total_pages": {
                          "type": "number"
                        },
                        "has_next": {
                          "type": "boolean"
                        },
                        "has_prev": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "page",
                        "limit",
                        "total",
                        "total_pages",
                        "has_next",
                        "has_prev"
                      ]
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "pagination",
                    "timestamp"
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Projects"
        ],
        "summary": "Create a project",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "example": "Staging"
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created project",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Project"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "409": {
            "description": "A project with this slug already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/projects/{id}": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "Get a project",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "8561efd0-99a4-481d-ab3f-9972767886c5"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The project",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Project"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Project not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Projects"
        ],
        "summary": "Update a project",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "8561efd0-99a4-481d-ab3f-9972767886c5"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1
                  },
                  "slug": {
                    "type": "string",
                    "minLength": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated project",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Project"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Project not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A project with this slug already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Projects"
        ],
        "summary": "Delete a project",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "8561efd0-99a4-481d-ab3f-9972767886c5"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "Project deleted"
          },
          "404": {
            "description": "Project not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Project still has endpoints",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/endpoints": {
      "get": {
        "tags": [
          "Endpoints"
        ],
        "summary": "List a project’s endpoints",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "prj_1ba9a8af7a7f4937a1838b9f535961dc"
            },
            "required": true,
            "name": "projectId",
            "in": "path"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "required": false,
            "name": "page",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "List of endpoints",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Endpoint"
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "page": {
                          "type": "number"
                        },
                        "limit": {
                          "type": "number"
                        },
                        "total": {
                          "type": "number"
                        },
                        "total_pages": {
                          "type": "number"
                        },
                        "has_next": {
                          "type": "boolean"
                        },
                        "has_prev": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "page",
                        "limit",
                        "total",
                        "total_pages",
                        "has_next",
                        "has_prev"
                      ]
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "pagination",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Project not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Endpoints"
        ],
        "summary": "Create an endpoint",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "prj_1ba9a8af7a7f4937a1838b9f535961dc"
            },
            "required": true,
            "name": "projectId",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "example": "Stripe production"
                  },
                  "provider": {
                    "type": "string",
                    "enum": [
                      "stripe",
                      "github",
                      "shopify",
                      "twilio",
                      "linear",
                      "custom"
                    ]
                  },
                  "secret": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Required for a known provider (stripe, github, shopify, twilio, linear)"
                  },
                  "verification_method": {
                    "type": "string",
                    "enum": [
                      "hmac_sha256",
                      "hmac_sha1",
                      "twilio_signature",
                      "bearer_token",
                      "basic_auth",
                      "jwt",
                      "ip_allowlist",
                      "none"
                    ],
                    "description": "Leave unset for a known provider (stripe, github, shopify, twilio, linear) to get its scheme and header automatically. Required for \"custom\" — including \"none\" if the endpoint should accept unsigned requests."
                  },
                  "verification_config": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "secret": {
                            "type": "string",
                            "minLength": 1
                          },
                          "header": {
                            "type": "string",
                            "minLength": 1
                          },
                          "prefix": {
                            "type": "string",
                            "description": "Which entry of a Stripe-style CSV header holds the digest, e.g. \"v1\""
                          },
                          "encoding": {
                            "type": "string",
                            "enum": [
                              "hex",
                              "base64"
                            ],
                            "description": "How the provider encodes the digest — hex unless stated otherwise (Shopify: base64)"
                          }
                        },
                        "required": [
                          "secret",
                          "header"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "object",
                        "properties": {
                          "token": {
                            "type": "string",
                            "minLength": 1
                          }
                        },
                        "required": [
                          "token"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "object",
                        "properties": {
                          "username": {
                            "type": "string",
                            "minLength": 1
                          },
                          "password": {
                            "type": "string",
                            "minLength": 1
                          }
                        },
                        "required": [
                          "username",
                          "password"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "object",
                        "properties": {
                          "jwks_url": {
                            "type": "string",
                            "minLength": 1
                          },
                          "audience": {
                            "type": "string"
                          },
                          "issuer": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "jwks_url"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "object",
                        "properties": {
                          "auth_token": {
                            "type": "string",
                            "minLength": 1
                          }
                        },
                        "required": [
                          "auth_token"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "object",
                        "properties": {
                          "ips": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "minLength": 1
                            },
                            "minItems": 1,
                            "description": "Literal addresses or IPv4 CIDR blocks — providers publish ranges",
                            "example": [
                              "13.110.0.0/16",
                              "54.187.174.169"
                            ]
                          }
                        },
                        "required": [
                          "ips"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "object",
                        "properties": {},
                        "additionalProperties": false
                      }
                    ]
                  }
                },
                "required": [
                  "name",
                  "provider"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created endpoint",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Endpoint"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Project not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/endpoints/{id}": {
      "get": {
        "tags": [
          "Endpoints"
        ],
        "summary": "Get an endpoint",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "end_8561efd099a4481dab3f9972767886c5"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The endpoint",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Endpoint"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Endpoints"
        ],
        "summary": "Update an endpoint",
        "description": "Takes up to 60 seconds to affect incoming webhooks: the ingest service caches endpoint configuration, and that cache expires rather than being purged.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "end_8561efd099a4481dab3f9972767886c5"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1
                  },
                  "provider": {
                    "type": "string",
                    "enum": [
                      "stripe",
                      "github",
                      "shopify",
                      "twilio",
                      "linear",
                      "custom"
                    ]
                  },
                  "secret": {
                    "type": "string",
                    "minLength": 1
                  },
                  "verification_method": {
                    "type": "string",
                    "enum": [
                      "hmac_sha256",
                      "hmac_sha1",
                      "twilio_signature",
                      "bearer_token",
                      "basic_auth",
                      "jwt",
                      "ip_allowlist",
                      "none"
                    ]
                  },
                  "verification_config": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "secret": {
                            "type": "string",
                            "minLength": 1
                          },
                          "header": {
                            "type": "string",
                            "minLength": 1
                          },
                          "prefix": {
                            "type": "string",
                            "description": "Which entry of a Stripe-style CSV header holds the digest, e.g. \"v1\""
                          },
                          "encoding": {
                            "type": "string",
                            "enum": [
                              "hex",
                              "base64"
                            ],
                            "description": "How the provider encodes the digest — hex unless stated otherwise (Shopify: base64)"
                          }
                        },
                        "required": [
                          "secret",
                          "header"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "object",
                        "properties": {
                          "token": {
                            "type": "string",
                            "minLength": 1
                          }
                        },
                        "required": [
                          "token"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "object",
                        "properties": {
                          "username": {
                            "type": "string",
                            "minLength": 1
                          },
                          "password": {
                            "type": "string",
                            "minLength": 1
                          }
                        },
                        "required": [
                          "username",
                          "password"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "object",
                        "properties": {
                          "jwks_url": {
                            "type": "string",
                            "minLength": 1
                          },
                          "audience": {
                            "type": "string"
                          },
                          "issuer": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "jwks_url"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "object",
                        "properties": {
                          "auth_token": {
                            "type": "string",
                            "minLength": 1
                          }
                        },
                        "required": [
                          "auth_token"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "object",
                        "properties": {
                          "ips": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "minLength": 1
                            },
                            "minItems": 1,
                            "description": "Literal addresses or IPv4 CIDR blocks — providers publish ranges",
                            "example": [
                              "13.110.0.0/16",
                              "54.187.174.169"
                            ]
                          }
                        },
                        "required": [
                          "ips"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "object",
                        "properties": {},
                        "additionalProperties": false
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated endpoint",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Endpoint"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Endpoints"
        ],
        "summary": "Delete an endpoint (soft delete)",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "end_8561efd099a4481dab3f9972767886c5"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "Endpoint deleted"
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/endpoints/{id}/test": {
      "post": {
        "tags": [
          "Endpoints"
        ],
        "summary": "Send a test webhook to this endpoint",
        "description": "Signs a sample payload with this endpoint's own verification config and posts it to its public ingest URL, so it goes through the same path a real provider event does: rate limiting, signature verification, fan-out to every active destination, and a recorded event you can then open, replay, or watch arrive in `catchook listen`.  Not every scheme can be tested this way, and the ones that cannot get a 400 saying why: `ip_allowlist` (the request comes from Catchook, never from an allowlisted address), `jwt` (a valid token has to be minted by whoever holds the key) and `twilio_signature` (Twilio signs the URL together with its sorted form parameters). For those, send a real event from the provider.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "end_8561efd099a4481dab3f9972767886c5"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The test was sent",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/TestEndpointResult"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "This endpoint's scheme cannot be tested this way",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Endpoint is paused, so a test would be rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The ingest service could not be reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/endpoints/{id}/pause": {
      "post": {
        "tags": [
          "Endpoints"
        ],
        "summary": "Pause an endpoint",
        "description": "Incoming webhooks are answered 409 while paused, and still recorded so the arrivals stay visible. Takes up to 60 seconds to affect incoming webhooks: the ingest service caches endpoint configuration, and that cache expires rather than being purged.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "end_8561efd099a4481dab3f9972767886c5"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The paused endpoint",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Endpoint"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/endpoints/{id}/resume": {
      "post": {
        "tags": [
          "Endpoints"
        ],
        "summary": "Resume a paused endpoint",
        "description": "Takes up to 60 seconds to affect incoming webhooks: the ingest service caches endpoint configuration, and that cache expires rather than being purged.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "end_8561efd099a4481dab3f9972767886c5"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The resumed endpoint",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Endpoint"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/endpoints/{id}/rotate-secret": {
      "post": {
        "tags": [
          "Endpoints"
        ],
        "summary": "Regenerate the verification secret (shown once)",
        "description": "The old secret stops being accepted once this takes effect. Takes up to 60 seconds to affect incoming webhooks: the ingest service caches endpoint configuration, and that cache expires rather than being purged.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "end_8561efd099a4481dab3f9972767886c5"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The new secret",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/EndpointWithSecret"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "This verification method does not support rotation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/api-keys": {
      "get": {
        "tags": [
          "API Keys"
        ],
        "summary": "List a project's API keys",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "8561efd0-99a4-481d-ab3f-9972767886c5"
            },
            "required": true,
            "name": "projectId",
            "in": "path"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "required": false,
            "name": "page",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "List of API keys (no secret)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ApiKey"
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "page": {
                          "type": "number"
                        },
                        "limit": {
                          "type": "number"
                        },
                        "total": {
                          "type": "number"
                        },
                        "total_pages": {
                          "type": "number"
                        },
                        "has_next": {
                          "type": "boolean"
                        },
                        "has_prev": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "page",
                        "limit",
                        "total",
                        "total_pages",
                        "has_next",
                        "has_prev"
                      ]
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "pagination",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Requires a signed-in session",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Project not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "API Keys"
        ],
        "summary": "Create an API key for a project",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "8561efd0-99a4-481d-ab3f-9972767886c5"
            },
            "required": true,
            "name": "projectId",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "example": "Default"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created API key (secret shown once)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ApiKeyCreated"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Requires a signed-in session",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Project not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api-keys/{id}": {
      "get": {
        "tags": [
          "API Keys"
        ],
        "summary": "Get an API key (no secret)",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "key_123"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The API key",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ApiKey"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Requires a signed-in session",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "API key not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "API Keys"
        ],
        "summary": "Revoke an API key",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "key_123"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "API key revoked"
          },
          "401": {
            "description": "Requires a signed-in session",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "API key not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/endpoints/{endpointId}/destinations": {
      "get": {
        "tags": [
          "Destinations"
        ],
        "summary": "List an endpoint's destinations",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "end_8561efd099a4481dab3f9972767886c5"
            },
            "required": true,
            "name": "endpointId",
            "in": "path"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "required": false,
            "name": "page",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "List of destinations",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Destination"
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "page": {
                          "type": "number"
                        },
                        "limit": {
                          "type": "number"
                        },
                        "total": {
                          "type": "number"
                        },
                        "total_pages": {
                          "type": "number"
                        },
                        "has_next": {
                          "type": "boolean"
                        },
                        "has_prev": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "page",
                        "limit",
                        "total",
                        "total_pages",
                        "has_next",
                        "has_prev"
                      ]
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "pagination",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Destinations"
        ],
        "summary": "Create a destination",
        "description": "A new destination starts receiving within a minute: takes up to 60 seconds to affect deliveries: the delivery service caches destination configuration, and that cache expires rather than being purged.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "end_8561efd099a4481dab3f9972767886c5"
            },
            "required": true,
            "name": "endpointId",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "example": "Main API"
                  },
                  "receiver_url": {
                    "type": "string",
                    "format": "uri",
                    "example": "https://api.my-saas.com/webhooks",
                    "description": "Must be https and public — private/link-local hosts are rejected"
                  },
                  "forward_original_signature": {
                    "type": "boolean"
                  },
                  "retry_max_attempts": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 10,
                    "description": "Default: 5, max: 10 (bounded by the delivery queue's own retry ceiling)"
                  },
                  "retry_backoff": {
                    "type": "string",
                    "enum": [
                      "exponential",
                      "linear",
                      "fixed"
                    ]
                  },
                  "rate_limit_max": {
                    "type": "integer",
                    "nullable": true,
                    "minimum": 1,
                    "description": "Max deliveries per window, null = unlimited"
                  },
                  "rate_limit_window": {
                    "type": "string",
                    "nullable": true,
                    "enum": [
                      "second",
                      "minute",
                      "hour",
                      "day",
                      null
                    ]
                  }
                },
                "required": [
                  "name",
                  "receiver_url"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created destination",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/DestinationWithSecret"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/destinations/{id}": {
      "get": {
        "tags": [
          "Destinations"
        ],
        "summary": "Get a destination",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "dst_777505a62a40472caf44ce6e951e31e0"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The destination",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Destination"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Destination not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Destinations"
        ],
        "summary": "Update a destination",
        "description": "Takes up to 60 seconds to affect deliveries: the delivery service caches destination configuration, and that cache expires rather than being purged.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "dst_777505a62a40472caf44ce6e951e31e0"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "example": "Main API"
                  },
                  "receiver_url": {
                    "type": "string",
                    "format": "uri",
                    "example": "https://api.my-saas.com/webhooks",
                    "description": "Must be https and public — private/link-local hosts are rejected"
                  },
                  "forward_original_signature": {
                    "type": "boolean"
                  },
                  "retry_max_attempts": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 10,
                    "description": "Default: 5, max: 10 (bounded by the delivery queue's own retry ceiling)"
                  },
                  "retry_backoff": {
                    "type": "string",
                    "enum": [
                      "exponential",
                      "linear",
                      "fixed"
                    ]
                  },
                  "rate_limit_max": {
                    "type": "integer",
                    "nullable": true,
                    "minimum": 1,
                    "description": "Max deliveries per window, null = unlimited"
                  },
                  "rate_limit_window": {
                    "type": "string",
                    "nullable": true,
                    "enum": [
                      "second",
                      "minute",
                      "hour",
                      "day",
                      null
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated destination",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Destination"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Destination not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Destinations"
        ],
        "summary": "Delete a destination (soft delete)",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "dst_777505a62a40472caf44ce6e951e31e0"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "204": {
            "description": "Destination deleted"
          },
          "404": {
            "description": "Destination not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/destinations/{id}/pause": {
      "post": {
        "tags": [
          "Destinations"
        ],
        "summary": "Pause a destination",
        "description": "Takes up to 60 seconds to affect deliveries: the delivery service caches destination configuration, and that cache expires rather than being purged.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "dst_777505a62a40472caf44ce6e951e31e0"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The paused destination",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Destination"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Destination not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/destinations/{id}/resume": {
      "post": {
        "tags": [
          "Destinations"
        ],
        "summary": "Resume a paused destination",
        "description": "Takes up to 60 seconds to affect deliveries: the delivery service caches destination configuration, and that cache expires rather than being purged.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "dst_777505a62a40472caf44ce6e951e31e0"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The resumed destination",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Destination"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Destination not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/destinations/{id}/rotate-secret": {
      "post": {
        "tags": [
          "Destinations"
        ],
        "summary": "Regenerate the catchook_secret used to sign deliveries",
        "description": "Deliveries are signed with the old secret until this takes effect, so give a receiver both for a minute — or expect a window of rejected deliveries. Takes up to 60 seconds to affect deliveries: the delivery service caches destination configuration, and that cache expires rather than being purged.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "dst_777505a62a40472caf44ce6e951e31e0"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The new secret",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/DestinationWithSecret"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Destination not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/events": {
      "get": {
        "tags": [
          "Events"
        ],
        "summary": "List an org's received events",
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "required": false,
            "name": "page",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "endpoint_id",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "stripe",
                "github",
                "shopify",
                "twilio",
                "linear",
                "custom"
              ]
            },
            "required": false,
            "name": "provider",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            },
            "required": false,
            "name": "signature_valid",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "required": false,
            "name": "from",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "required": false,
            "name": "to",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256,
              "description": "Free-text match against the raw payload and headers"
            },
            "required": false,
            "description": "Free-text match against the raw payload and headers",
            "name": "q",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 256,
              "pattern": "^(payload|headers)(\\.[^.]+)+$",
              "description": "Exact-match filter on a nested payload/headers field — always paired with `value`",
              "example": "payload.data.object.id"
            },
            "required": false,
            "description": "Exact-match filter on a nested payload/headers field — always paired with `value`",
            "name": "field",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 512,
              "description": "The value `field` must exactly equal",
              "example": "pi_1234"
            },
            "required": false,
            "description": "The value `field` must exactly equal",
            "name": "value",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            },
            "required": false,
            "name": "delivery_summary",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "List of events",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "page": {
                          "type": "number"
                        },
                        "limit": {
                          "type": "number"
                        },
                        "total": {
                          "type": "number"
                        },
                        "total_pages": {
                          "type": "number"
                        },
                        "has_next": {
                          "type": "boolean"
                        },
                        "has_prev": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "page",
                        "limit",
                        "total",
                        "total_pages",
                        "has_next",
                        "has_prev"
                      ]
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "pagination",
                    "timestamp"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/events/facets": {
      "get": {
        "tags": [
          "Events"
        ],
        "summary": "Aggregate counts for the events/attempts facet panel",
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "endpoint_id",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "stripe",
                "github",
                "shopify",
                "twilio",
                "linear",
                "custom"
              ]
            },
            "required": false,
            "name": "provider",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            },
            "required": false,
            "name": "signature_valid",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "required": false,
            "name": "from",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "required": false,
            "name": "to",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256,
              "description": "Free-text match against the raw payload and headers"
            },
            "required": false,
            "description": "Free-text match against the raw payload and headers",
            "name": "q",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 256,
              "pattern": "^(payload|headers)(\\.[^.]+)+$",
              "description": "Exact-match filter on a nested payload/headers field — always paired with `value`",
              "example": "payload.data.object.id"
            },
            "required": false,
            "description": "Exact-match filter on a nested payload/headers field — always paired with `value`",
            "name": "field",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 512,
              "description": "The value `field` must exactly equal",
              "example": "pi_1234"
            },
            "required": false,
            "description": "The value `field` must exactly equal",
            "name": "value",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Facet counts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/EventFacets"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/events/{eventId}": {
      "get": {
        "tags": [
          "Events"
        ],
        "summary": "Get an event, including its raw payload and every delivery attempt",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "evt_5f2b1c4a9e3d4f1a8b6c7d8e9f0a1b2c"
            },
            "required": true,
            "name": "eventId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The event",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/EventDetail"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Event not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/events/{eventId}/attempts": {
      "get": {
        "tags": [
          "Events"
        ],
        "summary": "List every delivery attempt for an event, oldest first",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "evt_5f2b1c4a9e3d4f1a8b6c7d8e9f0a1b2c"
            },
            "required": true,
            "name": "eventId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Delivery attempts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DeliveryAttempt"
                      }
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Event not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/events/{eventId}/replay": {
      "post": {
        "tags": [
          "Events"
        ],
        "summary": "Re-enqueue an event's payload to every active destination on its endpoint",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "evt_5f2b1c4a9e3d4f1a8b6c7d8e9f0a1b2c"
            },
            "required": true,
            "name": "eventId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Replay enqueued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ReplayResult"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Event not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/events/{eventId}/destinations/{destinationId}/replay": {
      "post": {
        "tags": [
          "Events"
        ],
        "summary": "Re-enqueue an event's payload to a single destination",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "evt_5f2b1c4a9e3d4f1a8b6c7d8e9f0a1b2c"
            },
            "required": true,
            "name": "eventId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "dst_5f2b1c4a9e3d4f1a8b6c7d8e9f0a1b2c"
            },
            "required": true,
            "name": "destinationId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Replay enqueued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ReplayDestinationResult"
                    },
                    "timestamp": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "timestamp"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Event or destination not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  }
}
