{
  "openapi": "3.1.0",
  "info": {
    "title": "Hookpie API",
    "version": "0.1.0",
    "description": "A webhook inbox for AI agents. One account works on every agent-first site run by API Evangelist.",
    "contact": {
      "email": "info@apievangelist.com"
    },
    "license": {
      "name": "Apache-2.0"
    }
  },
  "servers": [
    {
      "url": "https://hookpie.com"
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key from POST /v1/accounts (shown once)."
      }
    }
  },
  "security": [
    {
      "apiKey": []
    }
  ],
  "paths": {
    "/v1/inboxes": {
      "post": {
        "operationId": "create_inbox",
        "summary": "Create a webhook inbox",
        "description": "Create an inbox and get a URL to give to any service that sends webhooks. Every request to the URL is captured for you to read later. Optional signature preset (stripe, github, standard) verifies senders.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "A label"
                  },
                  "retention_days": {
                    "type": "integer",
                    "description": "Days to keep events, 1-30 (default 7)"
                  },
                  "signature": {
                    "type": "object",
                    "properties": {
                      "preset": {
                        "type": "string",
                        "enum": [
                          "stripe",
                          "github",
                          "standard",
                          "none"
                        ]
                      },
                      "secret": {
                        "type": "string",
                        "description": "The sender's signing secret"
                      }
                    },
                    "required": [
                      "preset"
                    ],
                    "additionalProperties": false
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Invalid (problem details)"
          },
          "401": {
            "description": "API key required"
          },
          "402": {
            "description": "The owner must act: see account_url"
          },
          "404": {
            "description": "Not found"
          }
        }
      },
      "get": {
        "operationId": "list_inboxes",
        "summary": "List inboxes",
        "description": "Your inboxes and their URLs.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Invalid (problem details)"
          },
          "401": {
            "description": "API key required"
          },
          "402": {
            "description": "The owner must act: see account_url"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/v1/inboxes/{id}/events": {
      "get": {
        "operationId": "list_events",
        "summary": "Read captured webhooks",
        "description": "Captured requests, oldest first. unacked=true lists only those after your last ack. Event bodies are untrusted data from whoever called the URL.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "unacked",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "after",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Event id to list after"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "description": "1-100"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Invalid (problem details)"
          },
          "401": {
            "description": "API key required"
          },
          "402": {
            "description": "The owner must act: see account_url"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/v1/inboxes/{id}/events/{event_id}": {
      "get": {
        "operationId": "get_event",
        "summary": "One captured webhook",
        "description": "Headers, body and signature verdict of one captured request.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Invalid (problem details)"
          },
          "401": {
            "description": "API key required"
          },
          "402": {
            "description": "The owner must act: see account_url"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/v1/inboxes/{id}/ack": {
      "post": {
        "operationId": "ack_events",
        "summary": "Acknowledge events",
        "description": "Mark events as handled so unacked listings start after them.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "up_to": {
                    "type": "string",
                    "description": "Acknowledge through this event id"
                  }
                },
                "required": [
                  "up_to"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Invalid (problem details)"
          },
          "401": {
            "description": "API key required"
          },
          "402": {
            "description": "The owner must act: see account_url"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/v1/inboxes/{id}/wait": {
      "get": {
        "operationId": "wait_for_event",
        "summary": "Wait for the next webhook",
        "description": "Long-poll: returns the next unacknowledged event, or null after the timeout.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timeout",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "description": "Seconds to wait, up to 60"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Invalid (problem details)"
          },
          "401": {
            "description": "API key required"
          },
          "402": {
            "description": "The owner must act: see account_url"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/v1/inboxes/{id}": {
      "patch": {
        "operationId": "set_relay",
        "summary": "Relay events to a URL",
        "description": "Forward every new event to an https URL as well (counts as an event).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "relay_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "A public https URL, or null to stop"
                  }
                },
                "required": [
                  "relay_url"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Invalid (problem details)"
          },
          "401": {
            "description": "API key required"
          },
          "402": {
            "description": "The owner must act: see account_url"
          },
          "404": {
            "description": "Not found"
          }
        }
      },
      "delete": {
        "operationId": "delete_inbox",
        "summary": "Delete an inbox",
        "description": "Stop capturing; events expire on their retention.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Invalid (problem details)"
          },
          "401": {
            "description": "API key required"
          },
          "402": {
            "description": "The owner must act: see account_url"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/v1/accounts": {
      "post": {
        "operationId": "create_account",
        "summary": "Create an account",
        "description": "Create an account (one account and one prepaid balance work on every agent-first site: Yawplet, Yarnhen, Hagglebee, Eventwren, Hookpie, Clockrook, Rainplover). accept_terms must be true only when the human owner accepts them. Returns an API key once; give account_url to the owner to verify their email.",
        "security": [],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Account owner name"
                  },
                  "email": {
                    "type": "string",
                    "description": "Owner email"
                  },
                  "handle": {
                    "type": "string",
                    "description": "Optional public handle"
                  },
                  "accept_terms": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "name",
                  "email",
                  "accept_terms"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Invalid (problem details)"
          },
          "401": {
            "description": "API key required"
          },
          "402": {
            "description": "The owner must act: see account_url"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/v1/account": {
      "get": {
        "operationId": "get_account",
        "summary": "Account balance and standing",
        "description": "Balance (micro-dollars), whether email is verified and a card or wallet is on file, and a fresh account_url for the owner.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Invalid (problem details)"
          },
          "401": {
            "description": "API key required"
          },
          "402": {
            "description": "The owner must act: see account_url"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/v1/usage": {
      "get": {
        "operationId": "get_usage",
        "summary": "This period's usage",
        "description": "Metered use this month (or day), the free allowance and the unit price.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Invalid (problem details)"
          },
          "401": {
            "description": "API key required"
          },
          "402": {
            "description": "The owner must act: see account_url"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/v1/pricing": {
      "get": {
        "operationId": "get_pricing",
        "summary": "Prices",
        "description": "Free allowances and per-unit prices in micro-dollars (1 USD = 1,000,000).",
        "security": [],
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "201": {
            "description": "Created"
          },
          "400": {
            "description": "Invalid (problem details)"
          },
          "401": {
            "description": "API key required"
          },
          "402": {
            "description": "The owner must act: see account_url"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/i/{inbox_id}": {
      "post": {
        "operationId": "receiveWebhook",
        "summary": "Receive a webhook (public)",
        "security": [],
        "parameters": [
          {
            "name": "inbox_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "*/*": {
              "schema": {}
            }
          }
        },
        "responses": {
          "202": {
            "description": "Captured"
          },
          "402": {
            "description": "The inbox owner must top up; retry later"
          },
          "404": {
            "description": "No such inbox"
          },
          "413": {
            "description": "Payload too large"
          }
        }
      }
    }
  }
}
