{
  "openapi" : "3.0.1",
  "info" : {
    "description" : "Read a project's published content, media and redirects, and send events into it, over HTTPS and JSON. This is the API\nyour website, app or backend calls at runtime.\n\n### Authentication\nSend a project API key in the `X-API-Key` header. Create keys in the dashboard under **Settings → API Keys**. A key\ncarries `read` and/or `write` permission and can be limited to a single project:\n\n- `read` — content, media, redirects and storefront reads.\n- `write` — ingesting events and engagement data.\n\nA key is shown once, when it is created. For anything shipped to a browser, use a read-only key limited to one project.\n\n### Responses\nBodies are JSON. Collections come back as `{ \"data\": [...], \"meta\": { ... } }`; each operation below shows its exact shape.\n\n### Caching\nContent responses carry `Cache-Control` and an `ETag`. Send the ETag back in `If-None-Match` to get `304 Not Modified`\nwith no body.\n\n### Errors\nEvery error response has the same shape. Branch on `error.code`, never on `error.message`, whose wording can change.\n\n```json\n{ \"error\": { \"code\": \"NOT_FOUND\", \"message\": \"Content entry not found: hello-world\" } }\n```\n\nValidation failures use `VALIDATION_ERROR` and list the offending fields under `error.details`.\n\n### Rate limits\nRequests are counted per API key (per client IP when no key is sent) in a fixed one-minute window. The default limit is\n100 requests per minute. Beyond it the API answers `429` with a `Retry-After` header giving the seconds until the\nwindow resets.\n",
    "title" : "Akorrah Delivery API",
    "version" : "v1"
  },
  "servers" : [ {
    "url" : "https://api.staging.akorrah.com"
  } ],
  "security" : [ {
    "apiKeyAuth" : [ ]
  } ],
  "tags" : [ {
    "description" : "Read published entries of your content types.",
    "name" : "Content"
  }, {
    "description" : "Sitemaps, robots.txt, llms.txt and per-entry structured data.",
    "name" : "SEO"
  }, {
    "description" : "Resized images and responsive `srcset` descriptors.",
    "name" : "Media"
  }, {
    "description" : "Resolve or bulk-load a project's redirect rules.",
    "name" : "Redirects"
  }, {
    "description" : "Products, cart quotes and checkout for digital commerce.",
    "name" : "Storefront"
  }, {
    "description" : "Activate and verify license keys from software you sell. No API key needed.",
    "name" : "Licensing"
  }, {
    "description" : "Send custom events from your own systems.",
    "name" : "Events"
  }, {
    "description" : "Identify people, record consent and preferences, and register devices.",
    "name" : "Engagement"
  } ],
  "paths" : {
    "/api/v1/content/{projectSlug}/_json-ld" : {
      "get" : {
        "description" : "The site's own `Organization` and `WebSite` as schema.org JSON-LD, for the home page. The organization carries the project's name, site URL and description, plus a logo and social profile links when the project has them. `WebSite` is omitted until the project has a site URL. Cached for 10 minutes.",
        "operationId" : "getSiteJsonLd",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/ld+json" : {
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : true
                }
              }
            },
            "description" : "A schema.org JSON-LD document."
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Get the site's JSON-LD",
        "tags" : [ "SEO" ]
      }
    },
    "/api/v1/content/{projectSlug}/_openapi" : {
      "get" : {
        "description" : "An OpenAPI 3 document generated from this project's own content types: a typed list and get operation for each, with a schema built from the type's fields. Feed it to a code generator to get types that match your content model. It is regenerated whenever a content type changes.",
        "operationId" : "getProjectOpenApi",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "An `ETag` from an earlier response. If it is still current the API answers `304 Not Modified` with no body.",
          "in" : "header",
          "name" : "If-None-Match",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : true
                }
              }
            },
            "description" : "The OpenAPI document."
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Get this project's OpenAPI document",
        "tags" : [ "Content" ]
      }
    },
    "/api/v1/content/{projectSlug}/_schema" : {
      "get" : {
        "description" : "The field definitions of every content type in the project. Use it to discover which fields an entry has, or to generate types. Returned as a bare array, not wrapped in `data`.",
        "operationId" : "listContentTypeSchemas",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "An `ETag` from an earlier response. If it is still current the API answers `304 Not Modified` with no body.",
          "in" : "header",
          "name" : "If-None-Match",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "$ref" : "#/components/schemas/ContentTypeResponse"
                  }
                }
              }
            },
            "description" : "Every content type, with its fields."
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "List content type schemas",
        "tags" : [ "Content" ]
      }
    },
    "/api/v1/content/{projectSlug}/_schema/{typeSlug}" : {
      "get" : {
        "description" : "The field definitions of a single content type. Returned unwrapped.",
        "operationId" : "getContentTypeSchema",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Slug of the content type, such as `blog-post`.",
          "in" : "path",
          "name" : "typeSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "An `ETag` from an earlier response. If it is still current the API answers `304 Not Modified` with no body.",
          "in" : "header",
          "name" : "If-None-Match",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ContentTypeResponse"
                }
              }
            },
            "description" : "The content type and its fields."
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Get one content type schema",
        "tags" : [ "Content" ]
      }
    },
    "/api/v1/content/{projectSlug}/llms.txt" : {
      "get" : {
        "description" : "A plain-text index of the project's published content for AI crawlers and agents. Cached for 10 minutes.",
        "operationId" : "getLlmsTxt",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "text/plain" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "description" : "OK"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Get llms.txt",
        "tags" : [ "SEO" ]
      }
    },
    "/api/v1/content/{projectSlug}/robots.txt" : {
      "get" : {
        "description" : "A robots.txt for the project, including a pointer to its sitemap. Cached for 10 minutes.",
        "operationId" : "getRobotsTxt",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "text/plain" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "description" : "OK"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Get robots.txt",
        "tags" : [ "SEO" ]
      }
    },
    "/api/v1/content/{projectSlug}/sitemap.xml" : {
      "get" : {
        "description" : "An XML sitemap of every published entry that has a canonical URL. Cached for 10 minutes.",
        "operationId" : "getSitemap",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/xml" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "description" : "OK"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Get sitemap.xml",
        "tags" : [ "SEO" ]
      }
    },
    "/api/v1/content/{projectSlug}/{typeSlug}" : {
      "get" : {
        "description" : "Published entries of a content type, paginated. Order is set with `sort` and is unspecified without it. For a **singleton** content type this returns the single entry directly, unwrapped, and the query and pagination parameters are ignored.\n\nResponses are cached and carry an `ETag`; send it back in `If-None-Match` to get a `304`.",
        "operationId" : "listContent",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Slug of the content type, such as `blog-post`.",
          "in" : "path",
          "name" : "typeSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Lifecycle status to list. Defaults to `PUBLISHED`. Any other value needs a key with `write` permission, and the response is never cached.",
          "in" : "query",
          "name" : "status",
          "required" : false,
          "schema" : {
            "type" : "string",
            "enum" : [ "PUBLISHED", "DRAFT", "ARCHIVED" ]
          }
        }, {
          "description" : "Comma-separated field slugs to return. `id` and `slug` are always included.",
          "example" : "title,excerpt",
          "in" : "query",
          "name" : "fields",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Comma-separated relation field slugs to resolve into `_expanded`. Only related entries that are published and in this project are included, as last published.",
          "example" : "author",
          "in" : "query",
          "name" : "expand",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "JSON filter on field values. Operators: `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$contains`, `$in`. Combine alternatives with `$or` (one level deep). URL-encode the JSON.",
          "example" : "{\"price\":{\"$gt\":29.99},\"tags\":{\"$contains\":\"featured\"}}",
          "in" : "query",
          "name" : "filter",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "`field:direction`, where direction is `asc` (default) or `desc`.",
          "example" : "publishedAt:desc",
          "in" : "query",
          "name" : "sort",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Free-text search across the content type's text fields.",
          "in" : "query",
          "name" : "search",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "1-based page number.",
          "in" : "query",
          "name" : "page",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32",
            "default" : 1
          }
        }, {
          "description" : "Entries per page.",
          "in" : "query",
          "name" : "pageSize",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32",
            "default" : 20
          }
        }, {
          "description" : "An `ETag` from an earlier response. If it is still current the API answers `304 Not Modified` with no body.",
          "in" : "header",
          "name" : "If-None-Match",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "examples" : {
                  "Blog posts" : {
                    "description" : "Blog posts",
                    "value" : {
                      "data" : [ {
                        "id" : "0b1f5d52-7d3e-4d1c-9a51-5c2f0a8e7e10",
                        "slug" : "hello-world",
                        "title" : "Hello, world",
                        "excerpt" : "Our first post.",
                        "author" : "9c2a3f0e-1c7b-4c58-8a0e-3c1b6f9d2a44",
                        "_expanded" : {
                          "author" : {
                            "id" : "9c2a3f0e-1c7b-4c58-8a0e-3c1b6f9d2a44",
                            "slug" : "ada-lovelace",
                            "status" : "PUBLISHED",
                            "data" : {
                              "name" : "Ada Lovelace"
                            }
                          }
                        }
                      } ],
                      "meta" : {
                        "page" : 1,
                        "pageSize" : 20,
                        "totalItems" : 1,
                        "totalPages" : 1
                      }
                    }
                  }
                },
                "schema" : {
                  "$ref" : "#/components/schemas/ContentEntryList"
                }
              }
            },
            "description" : "A page of entries.",
            "headers" : {
              "ETag" : {
                "description" : "Hash of the body. Send it as `If-None-Match` to get a `304`.",
                "schema" : {
                  "type" : "string"
                },
                "style" : "simple"
              }
            }
          },
          "304" : {
            "description" : "Not modified: the `If-None-Match` ETag is still current."
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "List entries",
        "tags" : [ "Content" ]
      }
    },
    "/api/v1/content/{projectSlug}/{typeSlug}/{entrySlug}" : {
      "get" : {
        "description" : "A single published entry, returned unwrapped. Cached and ETagged like the list endpoint, except preview requests, which are never cached.",
        "operationId" : "getContentEntry",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Slug of the content type, such as `blog-post`.",
          "in" : "path",
          "name" : "typeSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Slug of the entry.",
          "in" : "path",
          "name" : "entrySlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Comma-separated field slugs to return. `id` and `slug` are always included.",
          "in" : "query",
          "name" : "fields",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Comma-separated relation field slugs to resolve into `_expanded`. Only related entries that are published and in this project are included, as last published.",
          "in" : "query",
          "name" : "expand",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "A short-lived preview token from the dashboard. When valid, the response is the entry's current draft, served with `Cache-Control: no-store`.",
          "in" : "query",
          "name" : "preview",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "An `ETag` from an earlier response. If it is still current the API answers `304 Not Modified` with no body.",
          "in" : "header",
          "name" : "If-None-Match",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "examples" : {
                  "Blog post" : {
                    "description" : "Blog post",
                    "value" : {
                      "id" : "0b1f5d52-7d3e-4d1c-9a51-5c2f0a8e7e10",
                      "slug" : "hello-world",
                      "title" : "Hello, world",
                      "excerpt" : "Our first post."
                    }
                  }
                },
                "schema" : {
                  "$ref" : "#/components/schemas/ContentEntry"
                }
              }
            },
            "description" : "The entry."
          },
          "304" : {
            "description" : "Not modified: the `If-None-Match` ETag is still current."
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Get an entry by slug",
        "tags" : [ "Content" ]
      }
    },
    "/api/v1/content/{projectSlug}/{typeSlug}/{entrySlug}/hreflang" : {
      "get" : {
        "description" : "The published translations of this entry with each one's canonical URL, for `<link rel=\"alternate\" hreflang=\"…\">` tags.",
        "operationId" : "getEntryHreflang",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Slug of the content type, such as `blog-post`.",
          "in" : "path",
          "name" : "typeSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Slug of the entry.",
          "in" : "path",
          "name" : "entrySlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/HreflangList"
                }
              }
            },
            "description" : "One link per published translation, including this entry."
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Get an entry's hreflang links",
        "tags" : [ "SEO" ]
      }
    },
    "/api/v1/content/{projectSlug}/{typeSlug}/{entrySlug}/json-ld" : {
      "get" : {
        "description" : "schema.org structured data for the entry, ready to embed in a JSON-LD script tag (type `application/ld+json`). The type is chosen from the content type's fields: `FAQPage` for `question` and `answer` fields, or for a `faqs`, `faq` or `questions` list of `{question, answer}` objects; `HowTo` for a `steps` field; `Product` for a `price` field alongside `sku`, `inStock` or `brand`; `BlogPosting` for a body; otherwise `WebPage`. By default the response is that one node. With `graph=true` it is a `@graph` that also carries a `BreadcrumbList` and, for an article with a list of questions, its `FAQPage`. Cached for 10 minutes.",
        "operationId" : "getEntryJsonLd",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Slug of the content type, such as `blog-post`.",
          "in" : "path",
          "name" : "typeSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Slug of the entry.",
          "in" : "path",
          "name" : "entrySlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Return a `@graph` with the entry's breadcrumbs (and FAQ, if it has one) alongside the main node, instead of the main node alone.",
          "in" : "query",
          "name" : "graph",
          "required" : false,
          "schema" : {
            "type" : "boolean",
            "default" : false
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/ld+json" : {
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : true
                }
              }
            },
            "description" : "A schema.org JSON-LD document."
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Get an entry's JSON-LD",
        "tags" : [ "SEO" ]
      }
    },
    "/api/v1/content/{projectSlug}/{typeSlug}/{entrySlug}/open-graph" : {
      "get" : {
        "description" : "Open Graph and Twitter Card tags as a flat name-to-value object. Tags with no value are omitted. Cached for 10 minutes.",
        "operationId" : "getEntryOpenGraph",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Slug of the content type, such as `blog-post`.",
          "in" : "path",
          "name" : "typeSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Slug of the entry.",
          "in" : "path",
          "name" : "entrySlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "examples" : {
                  "Article" : {
                    "description" : "Article",
                    "value" : {
                      "og:title" : "Hello, world",
                      "og:type" : "article",
                      "og:url" : "https://example.com/blog/hello-world",
                      "og:site_name" : "Acme",
                      "twitter:card" : "summary",
                      "twitter:title" : "Hello, world"
                    }
                  }
                },
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : true
                }
              }
            },
            "description" : "Tag names mapped to values."
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Get an entry's Open Graph tags",
        "tags" : [ "SEO" ]
      }
    },
    "/api/v1/engagement/{projectSlug}/consent" : {
      "post" : {
        "description" : "Stores a consent decision and keeps the history. Campaigns and automations respect it when they send.",
        "operationId" : "recordConsent",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/ConsentRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "204" : {
            "description" : "Recorded."
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Record consent",
        "tags" : [ "Engagement" ]
      }
    },
    "/api/v1/engagement/{projectSlug}/deliveries/{deliveryId}/callback" : {
      "post" : {
        "description" : "For messages your own provider delivers: report what happened to a queued message. A repeated `providerEventId` is ignored, so it is safe to retry.",
        "operationId" : "reportDeliveryStatus",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "ID of the queued delivery.",
          "in" : "path",
          "name" : "deliveryId",
          "required" : true,
          "schema" : {
            "type" : "string",
            "format" : "uuid"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/DeliveryCallbackRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "204" : {
            "description" : "Applied, or already applied."
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Report a delivery status",
        "tags" : [ "Engagement" ]
      }
    },
    "/api/v1/engagement/{projectSlug}/devices" : {
      "post" : {
        "description" : "Attaches a push token to a person so push messages can reach that device.",
        "operationId" : "registerDevice",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/DeviceRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "204" : {
            "description" : "Registered."
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Register a device",
        "tags" : [ "Engagement" ]
      }
    },
    "/api/v1/engagement/{projectSlug}/identify" : {
      "post" : {
        "description" : "Finds the person by `distinctId` or `email`, or creates them, and updates their name. Returns their `contactId`; `anonymous` is true while only a `distinctId` is known.",
        "operationId" : "identifyPerson",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/IdentityRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object",
                  "example" : {
                    "contactId" : "6f1c9a52-3b1e-4d0a-8d33-2f8a0e6b7c11",
                    "distinctId" : "user_8841",
                    "anonymous" : false
                  }
                }
              }
            },
            "description" : "The person."
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Identify a person",
        "tags" : [ "Engagement" ]
      }
    },
    "/api/v1/engagement/{projectSlug}/in-app" : {
      "get" : {
        "description" : "The in-app messages currently waiting for a person, for rendering inside your product. Needs a key with `write` permission, like the rest of this API.",
        "operationId" : "listInAppMessages",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Your own stable ID for the person. Give this, `email`, or both.",
          "in" : "query",
          "name" : "distinctId",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "The person's email.",
          "in" : "query",
          "name" : "email",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "type" : "object",
                    "additionalProperties" : {
                      "type" : "object"
                    }
                  }
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "List in-app messages",
        "tags" : [ "Engagement" ]
      }
    },
    "/api/v1/engagement/{projectSlug}/preferences" : {
      "post" : {
        "description" : "Turns a channel or topic on or off for a person and optionally sets their time zone and quiet hours. Answers `400` (empty body) if a quiet-hours value isn't `HH:mm`.",
        "operationId" : "setPreference",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/PreferenceRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "204" : {
            "description" : "Saved."
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Set a delivery preference",
        "tags" : [ "Engagement" ]
      }
    },
    "/api/v1/engagement/{projectSlug}/whatsapp-otp/send" : {
      "post" : {
        "description" : "Sends a one-time code to a phone number over WhatsApp, for \"log in with WhatsApp\" or two-factor flows. Answers `400` with an `error` string if the code can't be sent.",
        "operationId" : "sendWhatsAppCode",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/WhatsAppOtpSendRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : {
                    "type" : "object"
                  }
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Send a WhatsApp login code",
        "tags" : [ "Engagement" ]
      }
    },
    "/api/v1/engagement/{projectSlug}/whatsapp-otp/verify" : {
      "post" : {
        "description" : "Checks a code sent by `whatsapp-otp/send`. Returns `{ \"verified\": true }` or `false`.",
        "operationId" : "verifyWhatsAppCode",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/WhatsAppOtpVerifyRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : {
                    "type" : "object"
                  }
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Verify a WhatsApp login code",
        "tags" : [ "Engagement" ]
      }
    },
    "/api/v1/events/{projectSlug}" : {
      "post" : {
        "description" : "Records a custom event against a person, which can then trigger automations and appear on their timeline. Needs a key with `write` permission. Events that fail validation are set aside for review and answered with `400` and no body.",
        "operationId" : "ingestEvent",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/EventPayload"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "202" : {
            "description" : "Accepted for processing."
          },
          "400" : {
            "description" : "Missing or invalid `eventName`, missing identity, or `eventData` isn't an object. Empty body."
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Send an event",
        "tags" : [ "Events" ]
      }
    },
    "/api/v1/media/{projectSlug}/{id}/render" : {
      "get" : {
        "description" : "Returns the image itself, resized and re-encoded on demand. Give `w`, `h` or both. With both, `fit=cover` (or `crop`) center-crops to fill the box exactly; any other `fit` scales to fit inside it, keeping the aspect ratio. Results are cached for an hour. The asset must be an image.\n\nThe request must carry your `X-API-Key` header, which a browser can't attach to an `<img>` tag. Call this from your server, an edge function or an image loader, not from page markup.",
        "operationId" : "renderImage",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "ID of the media asset.",
          "in" : "path",
          "name" : "id",
          "required" : true,
          "schema" : {
            "type" : "string",
            "format" : "uuid"
          }
        }, {
          "description" : "Target width in pixels.",
          "example" : 800,
          "in" : "query",
          "name" : "w",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        }, {
          "description" : "Target height in pixels.",
          "example" : 450,
          "in" : "query",
          "name" : "h",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        }, {
          "description" : "`cover` or `crop` to fill the `w`×`h` box exactly; anything else scales to fit inside it.",
          "example" : "cover",
          "in" : "query",
          "name" : "fit",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Output format. Defaults to `jpg`.",
          "in" : "query",
          "name" : "fm",
          "required" : false,
          "schema" : {
            "type" : "string",
            "enum" : [ "jpg", "jpeg", "png", "webp" ]
          }
        }, {
          "description" : "Compression quality, 1–100. Applies to `jpg` and `webp` only.",
          "example" : 80,
          "in" : "query",
          "name" : "q",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "image/jpeg" : {
                "schema" : {
                  "type" : "string",
                  "format" : "binary"
                }
              },
              "image/png" : {
                "schema" : {
                  "type" : "string",
                  "format" : "binary"
                }
              },
              "image/webp" : {
                "schema" : {
                  "type" : "string",
                  "format" : "binary"
                }
              }
            },
            "description" : "The rendered image."
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Render a resized image",
        "tags" : [ "Media" ]
      }
    },
    "/api/v1/media/{projectSlug}/{id}/srcset" : {
      "get" : {
        "description" : "Ready-made `srcset` markup for an image: one `/render` URL per width. Use `srcset` and `fallbackUrl` straight in an `<img>`, or `sources` to build your own.",
        "operationId" : "getImageSrcSet",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "ID of the media asset.",
          "in" : "path",
          "name" : "id",
          "required" : true,
          "schema" : {
            "type" : "string",
            "format" : "uuid"
          }
        }, {
          "description" : "Comma-separated widths in pixels. Defaults to 320, 640, 960, 1280, 1920.",
          "example" : "480,960,1440",
          "in" : "query",
          "name" : "widths",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Same as `fit` on `/render`.",
          "in" : "query",
          "name" : "fit",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Same as `fm` on `/render`.",
          "in" : "query",
          "name" : "fm",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Same as `q` on `/render`.",
          "in" : "query",
          "name" : "q",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiResponseSrcSetResult"
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Get a responsive srcset",
        "tags" : [ "Media" ]
      }
    },
    "/api/v1/redirects/{projectSlug}/all" : {
      "get" : {
        "description" : "Every active redirect as a bare array, for baking into static or edge routing config (for example a Next.js `redirects()` function or a Cloudflare Worker).",
        "operationId" : "listRedirects",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "$ref" : "#/components/schemas/RedirectResolution"
                  }
                }
              }
            },
            "description" : "OK"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "List all active redirects",
        "tags" : [ "Redirects" ]
      }
    },
    "/api/v1/redirects/{projectSlug}/resolve" : {
      "get" : {
        "description" : "Looks up the active redirect for a path, for resolving at the edge one request at a time. Responds `404` when the path has no active redirect. Each successful lookup counts as a hit.",
        "operationId" : "resolveRedirect",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "The request path to look up. A leading `/` is added if missing.",
          "example" : "/old-pricing",
          "in" : "query",
          "name" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/RedirectResolution"
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Resolve one path",
        "tags" : [ "Redirects" ]
      }
    },
    "/api/v1/store/license/activate" : {
      "post" : {
        "description" : "Registers a machine against a license key. Returns `success: false` with a `status` of `MAX_ACTIVATIONS_REACHED`, `EXPIRED` or `REVOKED` when the key can't be activated. Needs no API key; the license key is the credential.",
        "operationId" : "activateLicense",
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/LicenseActivateRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiResponseLicenseActivationResponse"
                }
              }
            },
            "description" : "The outcome of the activation."
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "404" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiResponseLicenseActivationResponse"
                }
              }
            },
            "description" : "No such license key."
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "security" : [ ],
        "summary" : "Activate a license on a machine",
        "tags" : [ "Licensing" ]
      }
    },
    "/api/v1/store/license/verify" : {
      "get" : {
        "description" : "Whether a license key is valid (not revoked and not expired), with its activation counts. Needs no API key.",
        "operationId" : "verifyLicense",
        "parameters" : [ {
          "description" : "The license key.",
          "in" : "query",
          "name" : "key",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiResponseLicenseVerifyResponse"
                }
              }
            },
            "description" : "Whether the key is valid, with its activation counts."
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "404" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiResponseLicenseVerifyResponse"
                }
              }
            },
            "description" : "No such license key."
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "security" : [ ],
        "summary" : "Verify a license key",
        "tags" : [ "Licensing" ]
      }
    },
    "/api/v1/store/{projectSlug}/cart/quote" : {
      "post" : {
        "description" : "Prices a cart without creating a checkout or using up a coupon, so a storefront can show live totals, including an automatically applied coupon, before the shopper pays.",
        "operationId" : "quoteCart",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/CartQuoteRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiResponseCartQuoteResponse"
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Quote a cart",
        "tags" : [ "Storefront" ]
      }
    },
    "/api/v1/store/{projectSlug}/checkout" : {
      "post" : {
        "description" : "Creates a Stripe Checkout session for the cart and returns its URL. Redirect the shopper to `checkoutUrl`; Stripe sends them back to `successUrl` or `cancelUrl`.",
        "operationId" : "createCheckout",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/CheckoutRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiResponseCheckoutResponse"
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Start a checkout",
        "tags" : [ "Storefront" ]
      }
    },
    "/api/v1/store/{projectSlug}/coupons/{code}" : {
      "get" : {
        "description" : "Whether a coupon code is currently redeemable, without needing a cart. Use it to confirm a `?coupon=CODE` landing-page link. Does not reveal usage counts or eligibility rules.",
        "operationId" : "previewCoupon",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "The coupon code.",
          "in" : "path",
          "name" : "code",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiResponseCouponPreviewResponse"
                }
              }
            },
            "description" : "OK"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Look up a coupon",
        "tags" : [ "Storefront" ]
      }
    },
    "/api/v1/store/{projectSlug}/products" : {
      "get" : {
        "description" : "Products that are currently available for sale, newest first, paginated. `priceCents` is in the smallest unit of `currency`.",
        "operationId" : "listProducts",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "1-based page number.",
          "in" : "query",
          "name" : "page",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32",
            "default" : 1
          }
        }, {
          "description" : "Products per page.",
          "in" : "query",
          "name" : "pageSize",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32",
            "default" : 20
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiResponseListStorefrontProductResponse"
                }
              }
            },
            "description" : "OK"
          },
          "400" : {
            "$ref" : "#/components/responses/BadRequest"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "List products",
        "tags" : [ "Storefront" ]
      }
    },
    "/api/v1/store/{projectSlug}/products/{slug}" : {
      "get" : {
        "description" : "One available product by the slug of its content entry. `data` holds the entry's own fields.",
        "operationId" : "getProduct",
        "parameters" : [ {
          "description" : "The project's slug, as shown in the dashboard.",
          "in" : "path",
          "name" : "projectSlug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "description" : "Slug of the product's content entry.",
          "in" : "path",
          "name" : "slug",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiResponseStorefrontProductResponse"
                }
              }
            },
            "description" : "OK"
          },
          "401" : {
            "$ref" : "#/components/responses/Unauthorized"
          },
          "404" : {
            "$ref" : "#/components/responses/NotFound"
          },
          "429" : {
            "$ref" : "#/components/responses/RateLimited"
          }
        },
        "summary" : "Get a product",
        "tags" : [ "Storefront" ]
      }
    }
  },
  "components" : {
    "responses" : {
      "BadRequest" : {
        "content" : {
          "application/json" : {
            "example" : {
              "error" : {
                "code" : "VALIDATION_ERROR",
                "message" : "Request validation failed"
              }
            },
            "schema" : {
              "$ref" : "#/components/schemas/ErrorResponse"
            }
          }
        },
        "description" : "The request was malformed or failed validation."
      },
      "NotFound" : {
        "content" : {
          "application/json" : {
            "example" : {
              "error" : {
                "code" : "NOT_FOUND",
                "message" : "Content entry not found: hello-world"
              }
            },
            "schema" : {
              "$ref" : "#/components/schemas/ErrorResponse"
            }
          }
        },
        "description" : "The project, content type or entry does not exist."
      },
      "RateLimited" : {
        "content" : {
          "application/json" : {
            "example" : {
              "error" : {
                "code" : "RATE_LIMITED",
                "message" : "Too many requests, slow down"
              }
            },
            "schema" : {
              "$ref" : "#/components/schemas/ErrorResponse"
            }
          }
        },
        "description" : "Too many requests. Wait for `Retry-After` seconds.",
        "headers" : {
          "Retry-After" : {
            "description" : "Seconds until the current rate-limit window resets.",
            "schema" : {
              "type" : "integer",
              "format" : "int32"
            }
          }
        }
      },
      "Unauthorized" : {
        "content" : {
          "application/json" : {
            "example" : {
              "error" : {
                "code" : "UNAUTHORIZED",
                "message" : "This endpoint requires a valid X-API-Key header"
              }
            },
            "schema" : {
              "$ref" : "#/components/schemas/ErrorResponse"
            }
          }
        },
        "description" : "The API key is missing, invalid, expired, lacks the permission this operation needs, or is limited to a different project."
      }
    },
    "schemas" : {
      "ApiError" : {
        "type" : "object",
        "properties" : {
          "code" : {
            "type" : "string",
            "description" : "Stable, machine-readable code. Branch on this, not on `message`.",
            "example" : "NOT_FOUND"
          },
          "details" : {
            "type" : "array",
            "description" : "Per-field problems; present on validation errors.",
            "items" : {
              "$ref" : "#/components/schemas/ErrorDetail"
            }
          },
          "message" : {
            "type" : "string",
            "description" : "Human-readable explanation. Wording may change.",
            "example" : "Content entry not found: hello-world"
          }
        }
      },
      "ApiResponseCartQuoteResponse" : {
        "type" : "object",
        "properties" : {
          "data" : {
            "$ref" : "#/components/schemas/CartQuoteResponse"
          },
          "meta" : {
            "$ref" : "#/components/schemas/PageMeta"
          }
        }
      },
      "ApiResponseCheckoutResponse" : {
        "type" : "object",
        "properties" : {
          "data" : {
            "$ref" : "#/components/schemas/CheckoutResponse"
          },
          "meta" : {
            "$ref" : "#/components/schemas/PageMeta"
          }
        }
      },
      "ApiResponseCouponPreviewResponse" : {
        "type" : "object",
        "properties" : {
          "data" : {
            "$ref" : "#/components/schemas/CouponPreviewResponse"
          },
          "meta" : {
            "$ref" : "#/components/schemas/PageMeta"
          }
        }
      },
      "ApiResponseLicenseActivationResponse" : {
        "type" : "object",
        "properties" : {
          "data" : {
            "$ref" : "#/components/schemas/LicenseActivationResponse"
          },
          "meta" : {
            "$ref" : "#/components/schemas/PageMeta"
          }
        }
      },
      "ApiResponseLicenseVerifyResponse" : {
        "type" : "object",
        "properties" : {
          "data" : {
            "$ref" : "#/components/schemas/LicenseVerifyResponse"
          },
          "meta" : {
            "$ref" : "#/components/schemas/PageMeta"
          }
        }
      },
      "ApiResponseListStorefrontProductResponse" : {
        "type" : "object",
        "properties" : {
          "data" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/StorefrontProductResponse"
            }
          },
          "meta" : {
            "$ref" : "#/components/schemas/PageMeta"
          }
        }
      },
      "ApiResponseSrcSetResult" : {
        "type" : "object",
        "properties" : {
          "data" : {
            "$ref" : "#/components/schemas/SrcSetResult"
          },
          "meta" : {
            "$ref" : "#/components/schemas/PageMeta"
          }
        }
      },
      "ApiResponseStorefrontProductResponse" : {
        "type" : "object",
        "properties" : {
          "data" : {
            "$ref" : "#/components/schemas/StorefrontProductResponse"
          },
          "meta" : {
            "$ref" : "#/components/schemas/PageMeta"
          }
        }
      },
      "CartQuoteRequest" : {
        "required" : [ "items" ],
        "type" : "object",
        "properties" : {
          "couponCode" : {
            "type" : "string"
          },
          "customerEmail" : {
            "type" : "string"
          },
          "items" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/CheckoutItemRequest"
            }
          }
        }
      },
      "CartQuoteResponse" : {
        "type" : "object",
        "properties" : {
          "appliedCouponCode" : {
            "type" : "string"
          },
          "autoApplied" : {
            "type" : "boolean"
          },
          "currency" : {
            "type" : "string"
          },
          "discountCents" : {
            "type" : "integer",
            "format" : "int32"
          },
          "subtotalCents" : {
            "type" : "integer",
            "format" : "int32"
          },
          "totalCents" : {
            "type" : "integer",
            "format" : "int32"
          }
        }
      },
      "CheckoutItemRequest" : {
        "required" : [ "productId" ],
        "type" : "object",
        "properties" : {
          "productId" : {
            "type" : "string",
            "format" : "uuid"
          },
          "quantity" : {
            "minimum" : 1,
            "type" : "integer",
            "format" : "int32"
          }
        }
      },
      "CheckoutRequest" : {
        "required" : [ "cancelUrl", "customerEmail", "items", "successUrl" ],
        "type" : "object",
        "properties" : {
          "cancelUrl" : {
            "type" : "string"
          },
          "couponCode" : {
            "type" : "string"
          },
          "customerEmail" : {
            "type" : "string"
          },
          "items" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/CheckoutItemRequest"
            }
          },
          "successUrl" : {
            "type" : "string"
          }
        }
      },
      "CheckoutResponse" : {
        "type" : "object",
        "properties" : {
          "checkoutUrl" : {
            "type" : "string"
          },
          "sessionId" : {
            "type" : "string"
          }
        }
      },
      "ConsentRequest" : {
        "required" : [ "channel", "status" ],
        "type" : "object",
        "properties" : {
          "channel" : {
            "type" : "string",
            "description" : "Channel the consent applies to.",
            "example" : "email"
          },
          "distinctId" : {
            "type" : "string",
            "description" : "Your own stable ID for the person."
          },
          "email" : {
            "type" : "string"
          },
          "ipAddress" : {
            "type" : "string",
            "description" : "The person's IP address at the time."
          },
          "policyVersion" : {
            "type" : "string",
            "description" : "Version of the policy the person agreed to.",
            "example" : "2026-01"
          },
          "source" : {
            "type" : "string",
            "description" : "Where consent was collected, for your audit trail.",
            "example" : "signup-form"
          },
          "status" : {
            "type" : "string",
            "description" : "The decision.",
            "example" : "GRANTED",
            "enum" : [ "GRANTED", "DENIED", "WITHDRAWN" ]
          },
          "topic" : {
            "type" : "string",
            "description" : "Narrows the consent to one topic, such as `newsletter`. Omit for the whole channel."
          }
        },
        "description" : "A consent decision for one channel, optionally scoped to a topic."
      },
      "ContentEntry" : {
        "type" : "object",
        "properties" : {
          "_expanded" : {
            "type" : "object",
            "additionalProperties" : {
              "$ref" : "#/components/schemas/ExpandedRelation"
            },
            "description" : "Present only when `expand` matched a relation field. Keys are relation field slugs; each value is a single summary, or an array of them for a multi-value relation."
          },
          "id" : {
            "type" : "string",
            "format" : "uuid",
            "example" : "0b1f5d52-7d3e-4d1c-9a51-5c2f0a8e7e10"
          },
          "slug" : {
            "type" : "string",
            "example" : "hello-world"
          }
        },
        "additionalProperties" : true,
        "description" : "A published entry. `id` and `slug` are always present; every other property is a field defined by the entry's content type (see `GET /_schema/{typeSlug}`)."
      },
      "ContentEntryList" : {
        "type" : "object",
        "properties" : {
          "data" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/ContentEntry"
            }
          },
          "meta" : {
            "$ref" : "#/components/schemas/PageMeta"
          }
        },
        "description" : "A page of entries plus pagination metadata."
      },
      "ContentTypeResponse" : {
        "type" : "object",
        "properties" : {
          "commerceEnabled" : {
            "type" : "boolean"
          },
          "createdAt" : {
            "type" : "string",
            "format" : "date-time"
          },
          "description" : {
            "type" : "string"
          },
          "displayField" : {
            "type" : "string"
          },
          "fields" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/FieldDefinition"
            }
          },
          "icon" : {
            "type" : "string"
          },
          "id" : {
            "type" : "string",
            "format" : "uuid"
          },
          "name" : {
            "type" : "string"
          },
          "previewUrlTemplate" : {
            "type" : "string"
          },
          "singleton" : {
            "type" : "boolean"
          },
          "slug" : {
            "type" : "string"
          },
          "sortOrder" : {
            "type" : "integer",
            "format" : "int32"
          },
          "sourceFile" : {
            "type" : "string"
          },
          "updatedAt" : {
            "type" : "string",
            "format" : "date-time"
          }
        }
      },
      "CouponPreviewResponse" : {
        "type" : "object",
        "properties" : {
          "autoApply" : {
            "type" : "boolean"
          },
          "code" : {
            "type" : "string"
          },
          "currentlyValid" : {
            "type" : "boolean"
          },
          "type" : {
            "type" : "string",
            "enum" : [ "PERCENTAGE", "FIXED_AMOUNT" ]
          },
          "value" : {
            "type" : "integer",
            "format" : "int32"
          }
        }
      },
      "DeliveryCallbackRequest" : {
        "required" : [ "status" ],
        "type" : "object",
        "properties" : {
          "errorMessage" : {
            "type" : "string",
            "description" : "Failure detail, when `status` is a failure."
          },
          "providerEventId" : {
            "type" : "string",
            "description" : "The provider's ID for this event. Resending the same one is a no-op."
          },
          "providerMessageId" : {
            "type" : "string",
            "description" : "The provider's ID for the message."
          },
          "status" : {
            "type" : "string",
            "example" : "DELIVERED",
            "enum" : [ "QUEUED", "SENT", "DELIVERED", "OPENED", "CLICKED", "FAILED", "BOUNCED", "COMPLAINED", "CANCELED" ]
          }
        },
        "description" : "A delivery-status update for a message sent through your own provider."
      },
      "DeviceRequest" : {
        "required" : [ "platform", "token" ],
        "type" : "object",
        "properties" : {
          "distinctId" : {
            "type" : "string",
            "description" : "Your own stable ID for the person."
          },
          "email" : {
            "type" : "string"
          },
          "platform" : {
            "type" : "string",
            "description" : "Device platform.",
            "example" : "ios"
          },
          "token" : {
            "type" : "string",
            "description" : "The push token issued by the platform."
          }
        },
        "description" : "A push-notification token for one of the person's devices."
      },
      "ErrorDetail" : {
        "type" : "object",
        "properties" : {
          "field" : {
            "type" : "string"
          },
          "message" : {
            "type" : "string"
          }
        },
        "description" : "Per-field problems; present on validation errors."
      },
      "ErrorResponse" : {
        "type" : "object",
        "properties" : {
          "error" : {
            "$ref" : "#/components/schemas/ApiError"
          }
        },
        "description" : "Body of every non-2xx response."
      },
      "EventPayload" : {
        "required" : [ "eventName" ],
        "type" : "object",
        "properties" : {
          "distinctId" : {
            "type" : "string",
            "description" : "Your own stable ID for the person. Required unless `email` is given.",
            "example" : "user_8841"
          },
          "email" : {
            "type" : "string",
            "description" : "The person's email. Required unless `distinctId` is given.",
            "example" : "ada@example.com"
          },
          "eventData" : {
            "type" : "object"
          },
          "eventName" : {
            "type" : "string",
            "description" : "What happened. Up to 255 characters.",
            "example" : "plan_upgraded"
          },
          "idempotencyKey" : {
            "type" : "string",
            "description" : "Send the same key again and the event is recorded only once.",
            "example" : "invoice_1042_paid"
          },
          "occurredAt" : {
            "type" : "string",
            "description" : "When it happened. Defaults to now.",
            "format" : "date-time",
            "example" : "2026-05-04T09:30:00Z"
          }
        },
        "description" : "One event. Identify who it belongs to with `distinctId`, `email`, or both. `eventData` holds free-form properties of the event and must be a JSON object. Sending the same `idempotencyKey` again records the event only once.",
        "example" : {
          "eventName" : "plan_upgraded",
          "distinctId" : "user_8841",
          "email" : "ada@example.com",
          "eventData" : {
            "plan" : "pro",
            "seats" : 5
          },
          "idempotencyKey" : "invoice_1042_paid"
        }
      },
      "ExpandedRelation" : {
        "type" : "object",
        "properties" : {
          "data" : {
            "type" : "object"
          },
          "id" : {
            "type" : "string",
            "format" : "uuid"
          },
          "slug" : {
            "type" : "string"
          },
          "status" : {
            "type" : "string",
            "description" : "Lifecycle status of the related entry.",
            "example" : "PUBLISHED"
          }
        },
        "description" : "Summary of a related entry, attached under `_expanded` when requested with `expand`. Only published entries of the same project are included, and `data` is what was last published. A related entry that is unpublished is left out, as if it did not exist."
      },
      "FieldDefinition" : {
        "type" : "object",
        "properties" : {
          "cardinality" : {
            "type" : "string",
            "enum" : [ "ONE_TO_ONE", "MANY_TO_ONE", "ONE_TO_MANY", "MANY_TO_MANY" ]
          },
          "description" : {
            "type" : "string"
          },
          "itemType" : {
            "type" : "string",
            "enum" : [ "TEXT", "LONG_TEXT", "RICH_TEXT", "NUMBER", "BOOLEAN", "DATE", "DATETIME", "MEDIA", "SELECT", "MULTI_SELECT", "LIST", "JSON", "RELATION", "SLUG", "EMAIL", "URL", "COLOR" ]
          },
          "name" : {
            "type" : "string"
          },
          "options" : {
            "type" : "array",
            "items" : {
              "type" : "string"
            }
          },
          "relatedType" : {
            "type" : "string",
            "deprecated" : true
          },
          "relatedTypes" : {
            "type" : "array",
            "items" : {
              "type" : "string"
            }
          },
          "required" : {
            "type" : "boolean"
          },
          "slug" : {
            "type" : "string"
          },
          "type" : {
            "type" : "string",
            "enum" : [ "TEXT", "LONG_TEXT", "RICH_TEXT", "NUMBER", "BOOLEAN", "DATE", "DATETIME", "MEDIA", "SELECT", "MULTI_SELECT", "LIST", "JSON", "RELATION", "SLUG", "EMAIL", "URL", "COLOR" ]
          },
          "validations" : {
            "type" : "object",
            "additionalProperties" : {
              "type" : "object"
            }
          },
          "weakReference" : {
            "type" : "boolean"
          }
        }
      },
      "HreflangLink" : {
        "type" : "object",
        "properties" : {
          "locale" : {
            "type" : "string",
            "description" : "Locale of the translation.",
            "example" : "fr"
          },
          "url" : {
            "type" : "string",
            "description" : "Canonical URL of the translation on the customer's site.",
            "example" : "https://example.com/fr/hello-world"
          }
        },
        "description" : "One alternate-language version of an entry."
      },
      "HreflangList" : {
        "type" : "object",
        "properties" : {
          "data" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/HreflangLink"
            }
          }
        }
      },
      "IdentityRequest" : {
        "type" : "object",
        "properties" : {
          "distinctId" : {
            "type" : "string",
            "description" : "Your own stable ID for the person.",
            "example" : "user_8841"
          },
          "email" : {
            "type" : "string",
            "example" : "ada@example.com"
          },
          "firstName" : {
            "type" : "string",
            "example" : "Ada"
          },
          "lastName" : {
            "type" : "string",
            "example" : "Lovelace"
          }
        },
        "description" : "Who the person is. Give `distinctId`, `email`, or both."
      },
      "LicenseActivateRequest" : {
        "required" : [ "keyValue", "machineId" ],
        "type" : "object",
        "properties" : {
          "keyValue" : {
            "type" : "string"
          },
          "machineId" : {
            "type" : "string"
          }
        }
      },
      "LicenseActivationResponse" : {
        "type" : "object",
        "properties" : {
          "message" : {
            "type" : "string"
          },
          "status" : {
            "type" : "string"
          },
          "success" : {
            "type" : "boolean"
          }
        }
      },
      "LicenseVerifyResponse" : {
        "type" : "object",
        "properties" : {
          "currentActivations" : {
            "type" : "integer",
            "format" : "int32"
          },
          "expiresAt" : {
            "type" : "string",
            "format" : "date-time"
          },
          "maxActivations" : {
            "type" : "integer",
            "format" : "int32"
          },
          "status" : {
            "type" : "string"
          },
          "valid" : {
            "type" : "boolean"
          }
        }
      },
      "PageMeta" : {
        "type" : "object",
        "properties" : {
          "page" : {
            "type" : "integer",
            "format" : "int32"
          },
          "pageSize" : {
            "type" : "integer",
            "format" : "int32"
          },
          "totalItems" : {
            "type" : "integer",
            "format" : "int64"
          },
          "totalPages" : {
            "type" : "integer",
            "format" : "int32"
          }
        }
      },
      "PreferenceRequest" : {
        "required" : [ "channel" ],
        "type" : "object",
        "properties" : {
          "channel" : {
            "type" : "string",
            "example" : "email"
          },
          "distinctId" : {
            "type" : "string",
            "description" : "Your own stable ID for the person."
          },
          "email" : {
            "type" : "string"
          },
          "enabled" : {
            "type" : "boolean",
            "description" : "Whether messages on this channel or topic are wanted."
          },
          "quietHoursEnd" : {
            "type" : "string",
            "description" : "End of quiet hours, `HH:mm`.",
            "example" : "07:00"
          },
          "quietHoursStart" : {
            "type" : "string",
            "description" : "Start of quiet hours, `HH:mm`.",
            "example" : "22:00"
          },
          "timezone" : {
            "type" : "string",
            "description" : "IANA time zone used for quiet hours.",
            "example" : "Europe/London"
          },
          "topic" : {
            "type" : "string",
            "description" : "Narrows the preference to one topic. Omit for the whole channel."
          }
        },
        "description" : "A person's delivery preference for one channel, optionally scoped to a topic."
      },
      "RedirectResolution" : {
        "type" : "object",
        "properties" : {
          "fromPath" : {
            "type" : "string"
          },
          "statusCode" : {
            "type" : "integer",
            "format" : "int32"
          },
          "toPath" : {
            "type" : "string"
          }
        }
      },
      "SrcSetEntry" : {
        "type" : "object",
        "properties" : {
          "url" : {
            "type" : "string"
          },
          "width" : {
            "type" : "integer",
            "format" : "int32"
          }
        }
      },
      "SrcSetResult" : {
        "type" : "object",
        "properties" : {
          "fallbackUrl" : {
            "type" : "string"
          },
          "sources" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/SrcSetEntry"
            }
          },
          "srcset" : {
            "type" : "string"
          }
        }
      },
      "StorefrontProductResponse" : {
        "type" : "object",
        "properties" : {
          "available" : {
            "type" : "boolean"
          },
          "billingPeriod" : {
            "type" : "string",
            "enum" : [ "MONTHLY", "YEARLY" ]
          },
          "compareAtPrice" : {
            "type" : "integer",
            "format" : "int32"
          },
          "currency" : {
            "type" : "string"
          },
          "data" : {
            "type" : "object"
          },
          "id" : {
            "type" : "string",
            "format" : "uuid"
          },
          "priceCents" : {
            "type" : "integer",
            "format" : "int32"
          },
          "productType" : {
            "type" : "string",
            "enum" : [ "DIGITAL", "SERVICE" ]
          },
          "recurring" : {
            "type" : "boolean"
          },
          "slug" : {
            "type" : "string"
          }
        }
      },
      "WhatsAppOtpSendRequest" : {
        "required" : [ "phone" ],
        "type" : "object",
        "properties" : {
          "accountId" : {
            "type" : "string",
            "description" : "WhatsApp account to send from. Defaults to the project's default account.",
            "format" : "uuid"
          },
          "phone" : {
            "type" : "string",
            "description" : "Phone number in international format.",
            "example" : "+447700900123"
          }
        }
      },
      "WhatsAppOtpVerifyRequest" : {
        "required" : [ "code", "phone" ],
        "type" : "object",
        "properties" : {
          "accountId" : {
            "type" : "string",
            "description" : "The account the code was sent from, if you specified one when sending.",
            "format" : "uuid"
          },
          "code" : {
            "type" : "string",
            "description" : "The code the person received.",
            "example" : "482913"
          },
          "phone" : {
            "type" : "string",
            "example" : "+447700900123"
          }
        }
      }
    },
    "securitySchemes" : {
      "apiKeyAuth" : {
        "description" : "A project API key from **Settings → API Keys** in the dashboard.",
        "in" : "header",
        "name" : "X-API-Key",
        "type" : "apiKey"
      }
    }
  }
}