{
  "openapi": "3.1.0",
  "info": {
    "title": "OK Payments API",
    "version": "0.1.0-preview",
    "description": "Preproduction contract. Live mode is blocked. API authentication is server-to-server; no browser CORS access. Core Stripe sandbox payment flows passed; deployed consumer acceptance and live activation remain pending."
  },
  "servers": [
    {
      "url": "https://okpmt.com",
      "description": "Planned production origin; not activated"
    },
    {
      "url": "http://127.0.0.1:9220",
      "description": "Private preview; all purchases disabled"
    }
  ],
  "components": {
    "securitySchemes": {
      "serverToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "Per-site, per-environment high-entropy server credential"
      }
    },
    "schemas": {
      "Quote": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "offer_id",
          "name",
          "mode",
          "currency",
          "unit_amount",
          "entitlements"
        ],
        "properties": {
          "offer_id": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.:@-]{0,127}$"
          },
          "name": {
            "type": "string",
            "maxLength": 120
          },
          "mode": {
            "enum": [
              "payment",
              "subscription"
            ]
          },
          "currency": {
            "type": "string",
            "pattern": "^[a-z]{3}$"
          },
          "unit_amount": {
            "type": "integer",
            "minimum": 1
          },
          "interval": {
            "enum": [
              "month",
              "year"
            ]
          },
          "entitlements": {
            "type": "object",
            "additionalProperties": {
              "type": "integer",
              "minimum": 0
            }
          },
          "requires_offer_id": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.:@-]{0,127}$"
          },
          "sellable": {
            "type": "boolean"
          }
        }
      }
    }
  },
  "paths": {
    "/healthz": {
      "get": {
        "summary": "Process liveness",
        "responses": {
          "200": {
            "description": "Process running; does not imply payment readiness"
          }
        }
      }
    },
    "/readyz": {
      "get": {
        "summary": "Payment readiness",
        "responses": {
          "200": {
            "description": "Test processor verified; production_ready remains false"
          },
          "503": {
            "description": "Preview or unavailable processor"
          }
        }
      }
    },
    "/.well-known/jwks.json": {
      "get": {
        "summary": "Event verification public key",
        "responses": {
          "200": {
            "description": "Ed25519 public JWK set"
          }
        }
      }
    },
    "/v1/checkouts": {
      "post": {
        "summary": "Create a hosted or embedded checkout",
        "description": "Requires checkout:write. See integration guide for fulfillment and retry rules. Supply exactly one of offer_id or quote. Hosted requires success_url and cancel_url only. Embedded requires return_url only. Custom quote requires quote:write plus configured permission. Initial creation returns201; replay returns200.",
        "security": [
          {
            "serverToken": []
          }
        ],
        "parameters": [
          {
            "name": "X-OKPMT-Environment",
            "in": "header",
            "required": true,
            "schema": {
              "enum": [
                "test",
                "preview"
              ]
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9_-]{16,128}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Invalid request or environment"
          },
          "401": {
            "description": "Invalid credential"
          },
          "403": {
            "description": "Scope or policy denied"
          },
          "409": {
            "description": "Conflict; reconcile before changing the request"
          },
          "503": {
            "description": "Payments unavailable or required configuration absent"
          },
          "201": {
            "description": "Checkout created; response includes payment_id, environment, status, ui_mode, expires_at and either url or client_secret"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "account_id",
                  "external_order_id",
                  "ui_mode"
                ],
                "properties": {
                  "account_id": {
                    "type": "string",
                    "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.:@-]{0,127}$"
                  },
                  "external_order_id": {
                    "type": "string",
                    "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.:@-]{0,127}$"
                  },
                  "offer_id": {
                    "type": "string",
                    "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.:@-]{0,127}$"
                  },
                  "quote": {
                    "$ref": "#/components/schemas/Quote"
                  },
                  "ui_mode": {
                    "enum": [
                      "hosted",
                      "embedded"
                    ]
                  },
                  "success_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Must exactly match a registered HTTPS return URL."
                  },
                  "cancel_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Must exactly match a registered HTTPS return URL."
                  },
                  "return_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Must exactly match a registered HTTPS return URL."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/portal-sessions": {
      "post": {
        "summary": "Create a restricted customer portal session",
        "description": "Requires portal:write. See integration guide for fulfillment and retry rules.",
        "security": [
          {
            "serverToken": []
          }
        ],
        "parameters": [
          {
            "name": "X-OKPMT-Environment",
            "in": "header",
            "required": true,
            "schema": {
              "enum": [
                "test",
                "preview"
              ]
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9_-]{16,128}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Invalid request or environment"
          },
          "401": {
            "description": "Invalid credential"
          },
          "403": {
            "description": "Scope or policy denied"
          },
          "409": {
            "description": "Conflict; reconcile before changing the request"
          },
          "503": {
            "description": "Payments unavailable or required configuration absent"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "account_id",
                  "return_url"
                ],
                "properties": {
                  "account_id": {
                    "type": "string",
                    "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.:@-]{0,127}$"
                  },
                  "return_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Must exactly match a registered HTTPS return URL."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/payments/{id}": {
      "get": {
        "summary": "Read a payment owned by this site and account",
        "description": "Requires billing:read. See integration guide for fulfillment and retry rules.",
        "security": [
          {
            "serverToken": []
          }
        ],
        "parameters": [
          {
            "name": "X-OKPMT-Environment",
            "in": "header",
            "required": true,
            "schema": {
              "enum": [
                "test",
                "preview"
              ]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "account_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.:@-]{0,127}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Invalid request or environment"
          },
          "401": {
            "description": "Invalid credential"
          },
          "403": {
            "description": "Scope or policy denied"
          },
          "409": {
            "description": "Conflict; reconcile before changing the request"
          },
          "503": {
            "description": "Payments unavailable or required configuration absent"
          }
        }
      }
    },
    "/v1/accounts/{account_id}": {
      "get": {
        "summary": "Read the local account projection",
        "description": "Requires billing:read. See integration guide for fulfillment and retry rules.",
        "security": [
          {
            "serverToken": []
          }
        ],
        "parameters": [
          {
            "name": "X-OKPMT-Environment",
            "in": "header",
            "required": true,
            "schema": {
              "enum": [
                "test",
                "preview"
              ]
            }
          },
          {
            "name": "account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.:@-]{0,127}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Invalid request or environment"
          },
          "401": {
            "description": "Invalid credential"
          },
          "403": {
            "description": "Scope or policy denied"
          },
          "409": {
            "description": "Conflict; reconcile before changing the request"
          },
          "503": {
            "description": "Payments unavailable or required configuration absent"
          }
        }
      }
    },
    "/v1/events": {
      "get": {
        "summary": "Read a page of freshly signed historical events",
        "description": "Requires reconcile:read. See integration guide for fulfillment and retry rules.",
        "security": [
          {
            "serverToken": []
          }
        ],
        "parameters": [
          {
            "name": "X-OKPMT-Environment",
            "in": "header",
            "required": true,
            "schema": {
              "enum": [
                "test",
                "preview"
              ]
            }
          },
          {
            "name": "after",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Invalid request or environment"
          },
          "401": {
            "description": "Invalid credential"
          },
          "403": {
            "description": "Scope or policy denied"
          },
          "409": {
            "description": "Conflict; reconcile before changing the request"
          },
          "503": {
            "description": "Payments unavailable or required configuration absent"
          }
        }
      }
    },
    "/v1/events/{id}": {
      "get": {
        "summary": "Read one exact signed event body",
        "description": "Requires reconcile:read. See integration guide for fulfillment and retry rules.",
        "security": [
          {
            "serverToken": []
          }
        ],
        "parameters": [
          {
            "name": "X-OKPMT-Environment",
            "in": "header",
            "required": true,
            "schema": {
              "enum": [
                "test",
                "preview"
              ]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Invalid request or environment"
          },
          "401": {
            "description": "Invalid credential"
          },
          "403": {
            "description": "Scope or policy denied"
          },
          "409": {
            "description": "Conflict; reconcile before changing the request"
          },
          "503": {
            "description": "Payments unavailable or required configuration absent"
          }
        }
      }
    },
    "/webhooks/stripe": {
      "post": {
        "summary": "Stripe event destination",
        "description": "Exact raw application/json body. Verify Stripe signature, pinned account, mode and API version. Never call from a browser.",
        "parameters": [
          {
            "name": "Stripe-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verified receipt recorded or duplicate acknowledged"
          },
          "400": {
            "description": "Invalid signature or processor context"
          },
          "409": {
            "description": "Reconciliation pending; retry"
          },
          "503": {
            "description": "Processor not ready"
          }
        }
      }
    }
  }
}
