{
  "openapi": "3.1.0",
  "info": {
    "title": "SimplyForms API",
    "version": "1.2.0",
    "description": "Public API of SimplyForms, an EU-hosted form backend that relays each submission to your inbox and stores none of it.\n\nSubmitting a form needs no API key: the `form_id` in the URL identifies the form, and the endpoint accepts requests from any origin. Reading and changing your form's settings needs the API key from your verification e-mail, sent in the `X-API-Key` header.\n\nEvery error is a JSON object with `ok: false`, a stable `code` and a `message` at the top level. The `detail` field repeats the same object for older clients; it is deprecated, read `code`.\n\nGuides and examples: https://simplyforms.app/en/docs",
    "contact": {
      "name": "SimplyForms support",
      "url": "https://simplyforms.app/en/docs",
      "email": "support@simplyforms.app"
    },
    "termsOfService": "https://simplyforms.app/en/legal/terms"
  },
  "servers": [
    {
      "url": "https://api.simplyforms.app",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Submissions",
      "description": "Send form submissions to the form owner's inbox."
    },
    {
      "name": "Spam protection",
      "description": "SimplyForms protection (ALTCHA) widget and challenges."
    },
    {
      "name": "Form settings",
      "description": "Read and change a form's configuration with your API key."
    },
    {
      "name": "Account",
      "description": "GDPR data export."
    }
  ],
  "paths": {
    "/v1/forms/{form_id}": {
      "post": {
        "tags": [
          "Submissions"
        ],
        "summary": "Submit a form",
        "description": "Relays a submission to the form owner's inbox. The submission is not stored. No API key is needed and any origin may call it, so you can post to it straight from a page, either with `fetch` (JSON response) or with a plain HTML `<form method=\"post\">` (the visitor is redirected to a thank-you page, see 303).",
        "operationId": "submitForm",
        "parameters": [
          {
            "name": "form_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Form Id"
            },
            "description": "Your form identifier from the dashboard (16-32 characters: letters, digits, `-`, `_`)."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The form fields. Every field whose name does not start with `_` appears in the notification e-mail; a non-empty `subject` field becomes the e-mail subject. Files sent as `multipart/form-data` are attached to the e-mail. The CAPTCHA token goes in `altcha` (SimplyForms protection) or `cf-turnstile-response` (Turnstile, and reCAPTCHA after copying the token there). `_redirect` only applies to plain HTML form posts, see the 303 response.",
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "_redirect": {
                    "type": "string",
                    "maxLength": 2048,
                    "description": "Where to send the visitor after a successful plain HTML form post: a path such as `/thanks`, or an absolute URL on the same origin as the page with the form. That page must be served over `https`, and its origin is taken from the `Referer` header, so a page that sends no Referer (`Referrer-Policy: no-referrer`) gets the SimplyForms confirmation page instead. Any other value is ignored. Not included in the e-mail.",
                    "examples": [
                      "/thanks"
                    ]
                  }
                },
                "additionalProperties": true
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "properties": {
                  "_redirect": {
                    "type": "string",
                    "maxLength": 2048,
                    "description": "Where to send the visitor after a successful plain HTML form post: a path such as `/thanks`, or an absolute URL on the same origin as the page with the form. That page must be served over `https`, and its origin is taken from the `Referer` header, so a page that sends no Referer (`Referrer-Policy: no-referrer`) gets the SimplyForms confirmation page instead. Any other value is ignored. Not included in the e-mail.",
                    "examples": [
                      "/thanks"
                    ]
                  }
                },
                "additionalProperties": true
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submission accepted and the notification e-mail handed to the mail server (API clients: `fetch`, XHR, servers).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmissionAccepted"
                }
              }
            }
          },
          "303": {
            "description": "Plain HTML form post without JavaScript: a `application/x-www-form-urlencoded` or `multipart/form-data` body sent as a browser navigation (`Sec-Fetch-Mode: navigate`, or in older browsers an `Accept` that prefers `text/html` and no `X-Requested-With`). Instead of JSON the visitor is redirected. On success to `_redirect` when it is valid, otherwise to the SimplyForms confirmation page (`https://simplyforms.app/en/sent`, Czech visitors `/sent`). On any error to the same page with `?error=<code>`: the code the JSON response would carry, except that CAPTCHA codes about the form's own setup become `CAPTCHA_FAILED`. When the browser sent a `Referer`, the page gets `back=<origin of the form page>` for a link back. Requests from `fetch`, XHR and servers, and JSON bodies, always get the JSON responses.",
            "headers": {
              "Location": {
                "description": "The redirect target.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "400": {
            "description": "Invalid submission: `CAPTCHA_FAILED`, `VALIDATION_FAILED`, `EMPTY_PAYLOAD`, `INVALID_JSON`, `INVALID_PAYLOAD`, `UNSUPPORTED_CONTENT_TYPE` or `INVALID_FORM_ID_FORMAT`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unknown or inactive form (`INVALID_FORM_ID`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The form does not accept submissions from this domain on its plan (`DOMAIN_LIMIT_EXCEEDED`; the FREE plan accepts one domain).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Attachments exceed the plan's file size limit (`FILE_SIZE_LIMIT_EXCEEDED`), uploads exceed the overall cap (`FILE_TOO_LARGE`) or the request body is too large (`PAYLOAD_TOO_LARGE`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The request does not match this operation's parameters or body (`INVALID_REQUEST`, details in `errors`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Daily submission limit or request rate exceeded (`DAILY_LIMIT_EXCEEDED` with `reset_date`, `RATE_LIMIT_EXCEEDED`), or the form owner's monthly e-mail limit and its grace allowance are used up (`MONTHLY_EMAIL_LIMIT_REACHED`, with `reset_date`). Nothing was sent. `RATE_LIMIT_EXCEEDED` and `MONTHLY_EMAIL_LIMIT_REACHED` carry a `Retry-After` header (seconds).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The submission could not be relayed; try again later (`SUBMISSION_FAILED`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The notification e-mail could not be handed to the mail server (`DELIVERY_FAILED`). Nothing was delivered and nothing else ran (no webhook, no autoresponder); try again later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/submit/{form_id}": {
      "post": {
        "tags": [
          "Submissions"
        ],
        "summary": "Submit a form (legacy path)",
        "description": "Permanent alias of `POST /v1/forms/{form_id}` with identical behaviour. Use the `/v1` path.",
        "operationId": "submitFormLegacy",
        "deprecated": true,
        "parameters": [
          {
            "name": "form_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Form Id"
            },
            "description": "Your form identifier from the dashboard (16-32 characters: letters, digits, `-`, `_`)."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The form fields. Every field whose name does not start with `_` appears in the notification e-mail; a non-empty `subject` field becomes the e-mail subject. Files sent as `multipart/form-data` are attached to the e-mail. The CAPTCHA token goes in `altcha` (SimplyForms protection) or `cf-turnstile-response` (Turnstile, and reCAPTCHA after copying the token there). `_redirect` only applies to plain HTML form posts, see the 303 response.",
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "_redirect": {
                    "type": "string",
                    "maxLength": 2048,
                    "description": "Where to send the visitor after a successful plain HTML form post: a path such as `/thanks`, or an absolute URL on the same origin as the page with the form. That page must be served over `https`, and its origin is taken from the `Referer` header, so a page that sends no Referer (`Referrer-Policy: no-referrer`) gets the SimplyForms confirmation page instead. Any other value is ignored. Not included in the e-mail.",
                    "examples": [
                      "/thanks"
                    ]
                  }
                },
                "additionalProperties": true
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "properties": {
                  "_redirect": {
                    "type": "string",
                    "maxLength": 2048,
                    "description": "Where to send the visitor after a successful plain HTML form post: a path such as `/thanks`, or an absolute URL on the same origin as the page with the form. That page must be served over `https`, and its origin is taken from the `Referer` header, so a page that sends no Referer (`Referrer-Policy: no-referrer`) gets the SimplyForms confirmation page instead. Any other value is ignored. Not included in the e-mail.",
                    "examples": [
                      "/thanks"
                    ]
                  }
                },
                "additionalProperties": true
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submission accepted and the notification e-mail handed to the mail server (API clients: `fetch`, XHR, servers).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmissionAccepted"
                }
              }
            }
          },
          "303": {
            "description": "Plain HTML form post without JavaScript: a `application/x-www-form-urlencoded` or `multipart/form-data` body sent as a browser navigation (`Sec-Fetch-Mode: navigate`, or in older browsers an `Accept` that prefers `text/html` and no `X-Requested-With`). Instead of JSON the visitor is redirected. On success to `_redirect` when it is valid, otherwise to the SimplyForms confirmation page (`https://simplyforms.app/en/sent`, Czech visitors `/sent`). On any error to the same page with `?error=<code>`: the code the JSON response would carry, except that CAPTCHA codes about the form's own setup become `CAPTCHA_FAILED`. When the browser sent a `Referer`, the page gets `back=<origin of the form page>` for a link back. Requests from `fetch`, XHR and servers, and JSON bodies, always get the JSON responses.",
            "headers": {
              "Location": {
                "description": "The redirect target.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "400": {
            "description": "Invalid submission: `CAPTCHA_FAILED`, `VALIDATION_FAILED`, `EMPTY_PAYLOAD`, `INVALID_JSON`, `INVALID_PAYLOAD`, `UNSUPPORTED_CONTENT_TYPE` or `INVALID_FORM_ID_FORMAT`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unknown or inactive form (`INVALID_FORM_ID`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The form does not accept submissions from this domain on its plan (`DOMAIN_LIMIT_EXCEEDED`; the FREE plan accepts one domain).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Attachments exceed the plan's file size limit (`FILE_SIZE_LIMIT_EXCEEDED`), uploads exceed the overall cap (`FILE_TOO_LARGE`) or the request body is too large (`PAYLOAD_TOO_LARGE`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The request does not match this operation's parameters or body (`INVALID_REQUEST`, details in `errors`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Daily submission limit or request rate exceeded (`DAILY_LIMIT_EXCEEDED` with `reset_date`, `RATE_LIMIT_EXCEEDED`), or the form owner's monthly e-mail limit and its grace allowance are used up (`MONTHLY_EMAIL_LIMIT_REACHED`, with `reset_date`). Nothing was sent. `RATE_LIMIT_EXCEEDED` and `MONTHLY_EMAIL_LIMIT_REACHED` carry a `Retry-After` header (seconds).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The submission could not be relayed; try again later (`SUBMISSION_FAILED`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The notification e-mail could not be handed to the mail server (`DELIVERY_FAILED`). Nothing was delivered and nothing else ran (no webhook, no autoresponder); try again later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/sf/challenge": {
      "get": {
        "tags": [
          "Spam protection"
        ],
        "summary": "Get an ALTCHA challenge",
        "description": "Issues a single-use proof-of-work challenge for the form's SimplyForms protection widget. Point the widget's `challengeurl` here. Also a quick way to check that a `form_id` exists and is active.",
        "operationId": "getAltchaChallenge",
        "parameters": [
          {
            "name": "form_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Form Id"
            },
            "description": "Your form identifier from the dashboard (16-32 characters: letters, digits, `-`, `_`)."
          }
        ],
        "responses": {
          "200": {
            "description": "A fresh challenge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AltchaChallenge"
                }
              }
            }
          },
          "404": {
            "description": "Unknown or inactive form (`FORM_NOT_FOUND`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The request does not match this operation's parameters or body (`INVALID_REQUEST`, details in `errors`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/sf/widget.js": {
      "get": {
        "tags": [
          "Spam protection"
        ],
        "summary": "Load the SimplyForms protection widget",
        "description": "JavaScript that defines the `<sf-captcha>` element. Load it once on any page with a protected form.",
        "operationId": "getAltchaWidget",
        "responses": {
          "200": {
            "description": "The widget script.",
            "content": {
              "text/javascript": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/user/{form_id}/captcha": {
      "get": {
        "tags": [
          "Form settings"
        ],
        "summary": "Get the CAPTCHA settings",
        "description": "The form's CAPTCHA configuration as the page with the form needs it: `type`, `enabled` and the provider's public settings, for example the site key, or the ALTCHA `challenge_url` and `widget_src`. Provider secrets are never returned.",
        "operationId": "getCaptchaSettings",
        "parameters": [
          {
            "name": "form_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Form Id"
            },
            "description": "Your form identifier from the dashboard (16-32 characters: letters, digits, `-`, `_`)."
          }
        ],
        "responses": {
          "200": {
            "description": "The CAPTCHA configuration under `captcha_config`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`MISSING_AUTH`, `INVALID_API_KEY`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The API key does not belong to this form (`ACCESS_DENIED`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The request does not match this operation's parameters or body (`INVALID_REQUEST`, details in `errors`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "put": {
        "tags": [
          "Form settings"
        ],
        "summary": "Change the CAPTCHA settings",
        "description": "Replaces the form's CAPTCHA configuration. A missing, null or empty provider secret keeps the stored one; send `clear_turnstile_secret_key` or `clear_recaptcha_secret_key` to remove it. Deploy the widget before you switch the type away from `none`, otherwise submissions without a token are rejected.",
        "operationId": "updateCaptchaSettings",
        "parameters": [
          {
            "name": "form_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Form Id"
            },
            "description": "Your form identifier from the dashboard (16-32 characters: letters, digits, `-`, `_`)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CaptchaSettingsUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Settings saved.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`MISSING_AUTH`, `INVALID_API_KEY`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The API key does not belong to this form (`ACCESS_DENIED`), or the plan does not include this CAPTCHA type (`FEATURE_NOT_AVAILABLE`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The request does not match this operation's parameters or body (`INVALID_REQUEST`, details in `errors`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/user/{form_id}/export": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Export your account data",
        "description": "Machine-readable export of the account (GDPR Art. 15 and 20): account and CAPTCHA settings, accepted legal documents, plan, and anonymous submission metrics. Submissions themselves are never stored, so they are not part of it. Call it with the account's first `form_id`.",
        "operationId": "exportAccountData",
        "parameters": [
          {
            "name": "form_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Form Id"
            },
            "description": "Your form identifier from the dashboard (16-32 characters: letters, digits, `-`, `_`)."
          }
        ],
        "responses": {
          "200": {
            "description": "The account data.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`MISSING_AUTH`, `INVALID_API_KEY`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The API key does not belong to this form (`ACCESS_DENIED`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The request does not match this operation's parameters or body (`INVALID_REQUEST`, details in `errors`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "AltchaChallenge": {
        "type": "object",
        "required": [
          "algorithm",
          "challenge",
          "max_number",
          "salt",
          "signature"
        ],
        "properties": {
          "algorithm": {
            "type": "string",
            "examples": [
              "SHA-256"
            ]
          },
          "challenge": {
            "type": "string"
          },
          "max_number": {
            "type": "integer"
          },
          "salt": {
            "type": "string"
          },
          "signature": {
            "type": "string"
          }
        }
      },
      "CaptchaSettingsUpdate": {
        "properties": {
          "type": {
            "type": "string",
            "title": "Type",
            "default": "none"
          },
          "turnstile_site_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Turnstile Site Key"
          },
          "turnstile_secret_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Turnstile Secret Key",
            "writeOnly": true,
            "format": "password"
          },
          "challenge_difficulty": {
            "type": "string",
            "title": "Challenge Difficulty",
            "default": "medium"
          },
          "altcha_difficulty": {
            "type": "string",
            "title": "Altcha Difficulty",
            "default": "medium"
          },
          "altcha_display_mode": {
            "type": "string",
            "enum": [
              "standard",
              "floating",
              "overlay",
              "invisible"
            ],
            "title": "Altcha Display Mode",
            "default": "standard"
          },
          "recaptcha_site_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Recaptcha Site Key"
          },
          "recaptcha_secret_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Recaptcha Secret Key",
            "writeOnly": true,
            "format": "password"
          },
          "recaptcha_version": {
            "type": "string",
            "title": "Recaptcha Version",
            "default": "v2"
          },
          "recaptcha_threshold": {
            "type": "number",
            "title": "Recaptcha Threshold",
            "default": 0.5
          },
          "recaptcha_theme": {
            "type": "string",
            "title": "Recaptcha Theme",
            "default": "light"
          },
          "recaptcha_size": {
            "type": "string",
            "title": "Recaptcha Size",
            "default": "normal"
          },
          "clear_turnstile_secret_key": {
            "type": "boolean",
            "title": "Clear Turnstile Secret Key",
            "default": false
          },
          "clear_recaptcha_secret_key": {
            "type": "boolean",
            "title": "Clear Recaptcha Secret Key",
            "default": false
          }
        },
        "type": "object",
        "title": "CaptchaSettingsUpdate",
        "description": "The complete CAPTCHA configuration. Provider secrets are write-only: a missing, null or empty secret keeps the stored one, and `clear_<secret field>: true` removes it."
      },
      "Error": {
        "type": "object",
        "description": "Every error of the public API. Read `code` and `message` at the top level; some codes add fields such as `reset_date` or `errors`.",
        "required": [
          "ok",
          "code",
          "message"
        ],
        "properties": {
          "ok": {
            "const": false
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code."
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation."
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Rule violations (`VALIDATION_FAILED`) or invalid request fields (`INVALID_REQUEST`)."
          },
          "reset_date": {
            "type": "string",
            "format": "date-time",
            "description": "When the limit resets (`DAILY_LIMIT_EXCEEDED`, `MONTHLY_EMAIL_LIMIT_REACHED`)."
          },
          "detail": {
            "type": "object",
            "deprecated": true,
            "description": "Deprecated copy of this error object (without `detail`), kept for clients that read `body.detail.code`. It will be removed in a future version; read `body.code`.",
            "required": [
              "ok",
              "code",
              "message"
            ],
            "properties": {
              "ok": {
                "const": false
              },
              "code": {
                "type": "string",
                "description": "Stable machine-readable error code."
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation."
              },
              "errors": {
                "type": "array",
                "items": {
                  "type": "object"
                },
                "description": "Rule violations (`VALIDATION_FAILED`) or invalid request fields (`INVALID_REQUEST`)."
              },
              "reset_date": {
                "type": "string",
                "format": "date-time",
                "description": "When the limit resets (`DAILY_LIMIT_EXCEEDED`, `MONTHLY_EMAIL_LIMIT_REACHED`)."
              }
            },
            "additionalProperties": true
          }
        },
        "additionalProperties": true
      },
      "SubmissionAccepted": {
        "type": "object",
        "required": [
          "success"
        ],
        "properties": {
          "success": {
            "const": true
          }
        }
      }
    },
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "The API key from your verification e-mail. Keep it out of client-side code."
      }
    }
  }
}
