{
  "openapi": "3.1.0",
  "info": {
    "title": "Nautilinks Agent API",
    "version": "1.0.0",
    "description": "Machine-to-machine API for searching the Nautilinks backlink catalog, creating guarded orders, tracking publication, and subscribing to signed webhooks. Live and sandbox keys use the same endpoint; a sandbox key has the `sn_test_` prefix and never creates or charges a real order.",
    "contact": {
      "name": "Nautilinks developer support",
      "url": "https://nautilinks.co/en/developers/",
      "email": "contact@nautilinks.co"
    },
    "license": {
      "name": "Proprietary — Nautilinks API terms",
      "url": "https://nautilinks.co/en/terms/"
    }
  },
  "externalDocs": {
    "description": "Nautilinks developer portal and quickstart",
    "url": "https://nautilinks.co/en/developers/"
  },
  "servers": [
    {
      "url": "https://nautilinks.co/api/v1/agent",
      "description": "Nautilinks production and sandbox API"
    }
  ],
  "security": [{ "bearerAuth": [] }],
  "tags": [
    { "name": "Catalog", "description": "Read-only placement discovery." },
    { "name": "Commerce", "description": "Balance, order, quote, and delivery lifecycle." },
    { "name": "Webhooks", "description": "Signed order lifecycle notifications." },
    { "name": "AI visibility", "description": "Read-only projects and order-ready opportunity plans." }
  ],
  "paths": {
    "/catalog": {
      "get": {
        "operationId": "searchCatalogSites",
        "summary": "Search backlink placements",
        "description": "Returns visible Nautilinks publisher sites across the Plancton, Corail, and Nautilus fixed-price shelves. All filters are optional and combined with AND semantics.",
        "tags": ["Catalog"],
        "parameters": [
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Offset" },
          { "name": "niche", "in": "query", "description": "Exact lowercase niche slug.", "schema": { "type": "string", "minLength": 1 } },
          { "name": "language", "in": "query", "description": "Exact lowercase content language code.", "schema": { "type": "string", "minLength": 2, "maxLength": 10 } },
          { "name": "min_tf", "in": "query", "description": "Minimum Majestic Trust Flow.", "schema": { "type": "integer", "minimum": 0 } },
          { "name": "max_price", "in": "query", "description": "Maximum placement price in euros.", "schema": { "type": "integer", "minimum": 0 } },
          { "name": "q", "in": "query", "description": "Case-insensitive text search over domain and niche label.", "schema": { "type": "string", "minLength": 1, "maxLength": 200 } },
          { "name": "shelf", "in": "query", "description": "Restrict results to one fixed-price shelf.", "schema": { "$ref": "#/components/schemas/PriceShelf" } }
        ],
        "responses": {
          "200": { "description": "A typed page of catalog sites and shelf metadata.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CatalogResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "default": { "$ref": "#/components/responses/UnexpectedError" }
        }
      }
    },
    "/catalog/{siteId}": {
      "get": {
        "operationId": "getCatalogSite",
        "summary": "Get one catalog site",
        "description": "Returns the metrics, language, niche, fixed shelf, and price for one visible sellable site.",
        "tags": ["Catalog"],
        "parameters": [{ "$ref": "#/components/parameters/SiteId" }],
        "responses": {
          "200": { "description": "The requested catalog site.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SiteResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "default": { "$ref": "#/components/responses/UnexpectedError" }
        }
      }
    },
    "/catalog/{siteId}/articles": {
      "get": {
        "operationId": "listCatalogSiteArticles",
        "summary": "List available insertion articles",
        "description": "Lists sold-once existing articles available on a catalog site, with ranking queries and performance data. Identity fields stay masked until the site has been delivered to the buyer.",
        "tags": ["Catalog"],
        "parameters": [
          { "$ref": "#/components/parameters/SiteId" },
          { "name": "limit", "in": "query", "description": "Maximum articles to return.", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } }
        ],
        "responses": {
          "200": { "description": "Available articles for this site.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ArticlesResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "default": { "$ref": "#/components/responses/UnexpectedError" }
        }
      }
    },
    "/balance": {
      "get": {
        "operationId": "getPrepaidBalance",
        "summary": "Get prepaid balance",
        "description": "Returns the account's prepaid credit so an agent can determine whether an order may settle immediately or require a human-approved Stripe payment link.",
        "tags": ["Commerce"],
        "responses": {
          "200": { "description": "Current prepaid balance.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BalanceResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "default": { "$ref": "#/components/responses/UnexpectedError" }
        }
      }
    },
    "/orders": {
      "get": {
        "operationId": "listOrders",
        "summary": "List account orders",
        "description": "Lists orders owned by the API-key account, newest state included.",
        "tags": ["Commerce"],
        "responses": {
          "200": { "description": "Order summaries.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrderListResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "default": { "$ref": "#/components/responses/UnexpectedError" }
        }
      },
      "post": {
        "operationId": "createOrder",
        "summary": "Create or simulate an order",
        "description": "Creates a 1-20 item backlink order. A live key may spend existing prepaid credit immediately; any card remainder is returned as a Stripe URL that a human must open. A sandbox key validates and prices the same payload without writes or charges. Reuse the same Idempotency-Key after timeouts.",
        "tags": ["Commerce"],
        "parameters": [{ "$ref": "#/components/parameters/IdempotencyKey" }],
        "requestBody": {
          "required": true,
          "description": "The desired placements and optional discount/sandbox balance simulation.",
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateOrderRequest" } } }
        },
        "responses": {
          "200": { "description": "Created, pending-payment, or sandbox order result. Inspect `payment_url`, `sandbox`, and `order_status` instead of assuming money moved.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateOrderResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" },
          "default": { "$ref": "#/components/responses/UnexpectedError" }
        }
      }
    },
    "/orders/{orderId}": {
      "get": {
        "operationId": "getOrder",
        "summary": "Get order and placement status",
        "description": "Returns one owned order and the lifecycle state of each link, including the published URL when available.",
        "tags": ["Commerce"],
        "parameters": [{ "$ref": "#/components/parameters/OrderId" }],
        "responses": {
          "200": { "description": "Detailed order status.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrderResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "default": { "$ref": "#/components/responses/UnexpectedError" }
        }
      }
    },
    "/quotes/{quoteId}": {
      "get": {
        "operationId": "getQuote",
        "summary": "Get quote payment status",
        "description": "Polls a pending quote after a human receives a payment URL and returns the resulting order identifier once conversion completes.",
        "tags": ["Commerce"],
        "parameters": [{ "$ref": "#/components/parameters/QuoteId" }],
        "responses": {
          "200": { "description": "Quote, payment split, and resulting order state.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QuoteResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "default": { "$ref": "#/components/responses/UnexpectedError" }
        }
      }
    },
    "/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "summary": "List webhook subscriptions",
        "description": "Lists active and revoked webhook subscriptions owned by the API-key account.",
        "tags": ["Webhooks"],
        "responses": {
          "200": { "description": "Webhook subscriptions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookListResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "default": { "$ref": "#/components/responses/UnexpectedError" }
        }
      },
      "post": {
        "operationId": "createWebhook",
        "summary": "Create a signed webhook subscription",
        "description": "Registers a public HTTPS callback for selected order events. The response reveals the signing secret once; deliveries use the Nautilinks-Signature HMAC-SHA256 header.",
        "tags": ["Webhooks"],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateWebhookRequest" } } }
        },
        "responses": {
          "200": { "description": "Created subscription and one-time secret.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateWebhookResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "default": { "$ref": "#/components/responses/UnexpectedError" }
        }
      }
    },
    "/webhooks/{webhookId}": {
      "delete": {
        "operationId": "revokeWebhook",
        "summary": "Revoke a webhook subscription",
        "description": "Soft-revokes one owned webhook subscription. Historical delivery records are retained.",
        "tags": ["Webhooks"],
        "parameters": [{ "$ref": "#/components/parameters/WebhookId" }],
        "responses": {
          "200": { "description": "Subscription revoked.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "default": { "$ref": "#/components/responses/UnexpectedError" }
        }
      }
    },
    "/ai-visibility/projects": {
      "get": {
        "operationId": "listAiVisibilityProjects",
        "summary": "List AI visibility projects",
        "description": "Lists the AI visibility projects owned by the API-key account. This operation is read-only.",
        "tags": ["AI visibility"],
        "responses": {
          "200": { "description": "Owned projects.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectListResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "default": { "$ref": "#/components/responses/UnexpectedError" }
        }
      }
    },
    "/ai-visibility/projects/{projectId}/plan": {
      "get": {
        "operationId": "getAiVisibilityPlan",
        "summary": "Get an order-ready AI visibility plan",
        "description": "Returns uncited opportunities as typed items that can be reviewed and passed to createOrder. This operation never creates a cart, quote, order, or charge.",
        "tags": ["AI visibility"],
        "parameters": [{ "$ref": "#/components/parameters/ProjectId" }],
        "responses": {
          "200": { "description": "Project and order-ready plan items.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlanResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "default": { "$ref": "#/components/responses/UnexpectedError" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "sn_live_<40 hex> or sn_test_<40 hex>",
        "description": "Create a live or sandbox key in the Nautilinks member area. Send it on every request; never put it in a URL."
      }
    },
    "parameters": {
      "Limit": { "name": "limit", "in": "query", "description": "Maximum sites in this page.", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } },
      "Offset": { "name": "offset", "in": "query", "description": "Zero-based result offset.", "schema": { "type": "integer", "minimum": 0, "default": 0 } },
      "SiteId": { "name": "siteId", "in": "path", "required": true, "description": "Positive catalog site identifier.", "schema": { "type": "integer", "minimum": 1 } },
      "OrderId": { "name": "orderId", "in": "path", "required": true, "description": "Order identifier returned by createOrder or getQuote.", "schema": { "type": "string", "minLength": 1 } },
      "QuoteId": { "name": "quoteId", "in": "path", "required": true, "description": "Quote identifier returned by createOrder when payment is pending.", "schema": { "type": "string", "minLength": 1 } },
      "WebhookId": { "name": "webhookId", "in": "path", "required": true, "description": "Webhook subscription identifier.", "schema": { "type": "string", "minLength": 1 } },
      "ProjectId": { "name": "projectId", "in": "path", "required": true, "description": "Positive AI visibility project identifier.", "schema": { "type": "integer", "minimum": 1 } },
      "IdempotencyKey": { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Stable caller-generated key for safe write retries. Reusing a key with a different body returns 409.", "schema": { "type": "string", "minLength": 1, "maxLength": 200 } }
    },
    "responses": {
      "BadRequest": { "description": "The request is syntactically or semantically invalid.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Unauthorized": { "description": "The API key is missing, invalid, or revoked.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Forbidden": { "description": "The key lacks the required scope or resource ownership.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "NotFound": { "description": "The resource does not exist or is not visible to this account.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Conflict": { "description": "The request conflicts with current inventory, payment, or idempotency state.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "RateLimited": { "description": "The request quota or rolling daily order cap was reached.", "headers": { "Retry-After": { "description": "Seconds the caller must wait before retrying.", "required": true, "schema": { "type": "integer", "minimum": 1 } }, "RateLimit": { "$ref": "#/components/headers/RateLimit" }, "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "InternalServerError": { "description": "Nautilinks encountered an unexpected internal error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "ServiceUnavailable": { "description": "A required payment or upstream service is temporarily unavailable.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "UnexpectedError": { "description": "Any non-success status not listed explicitly uses the same typed error envelope.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    },
    "headers": {
      "RateLimit": { "description": "Current quota name, remaining requests, and seconds until reset, encoded as an HTTP Structured Field Dictionary.", "schema": { "type": "string", "example": "\"agent-api\";r=599;t=42" } },
      "RateLimitPolicy": { "description": "Quota name, request limit, and window in seconds, encoded as an HTTP Structured Field List.", "schema": { "type": "string", "example": "\"agent-api\";q=600;w=60" } }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "additionalProperties": true,
        "required": ["ok", "error", "code", "message", "resolution"],
        "properties": {
          "ok": { "type": "boolean", "const": false },
          "error": { "type": "string", "description": "Backward-compatible stable error code." },
          "code": { "type": "string", "description": "Stable machine-readable error code." },
          "message": { "type": "string", "description": "Human-readable explanation." },
          "resolution": { "type": "string", "description": "Concrete recovery hint for an agent." }
        }
      },
      "OkResponse": { "type": "object", "additionalProperties": false, "required": ["ok"], "properties": { "ok": { "type": "boolean", "const": true } } },
      "PriceShelf": { "type": "string", "enum": ["Plancton", "Corail", "Nautilus"] },
      "ShelfInfo": { "type": "object", "additionalProperties": false, "required": ["price_eur", "description"], "properties": { "price_eur": { "type": "number", "minimum": 0 }, "description": { "type": "string" } } },
      "Site": {
        "type": "object",
        "additionalProperties": true,
        "required": ["id", "niche_label", "language", "price_eur", "price_shelf"],
        "properties": {
          "id": { "type": "integer", "minimum": 1 },
          "domain": { "type": ["string", "null"] },
          "niche_label": { "type": "string" },
          "category": { "type": ["string", "null"] },
          "language": { "type": "string" },
          "tf": { "type": ["integer", "null"], "minimum": 0 },
          "cf": { "type": ["integer", "null"], "minimum": 0 },
          "rd": { "type": ["integer", "null"], "minimum": 0 },
          "moz_da": { "type": ["integer", "null"], "minimum": 0 },
          "traffic_monthly": { "type": ["integer", "null"], "minimum": 0 },
          "keywords_ranked": { "type": ["integer", "null"], "minimum": 0 },
          "price_eur": { "type": ["number", "null"], "minimum": 0 },
          "price_shelf": { "oneOf": [{ "$ref": "#/components/schemas/PriceShelf" }, { "type": "null" }] }
        }
      },
      "CatalogResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["ok", "count", "total", "limit", "offset", "sites", "shelves"],
        "properties": {
          "ok": { "type": "boolean", "const": true },
          "count": { "type": "integer", "minimum": 0 },
          "total": { "type": "integer", "minimum": 0 },
          "limit": { "type": "integer", "minimum": 1 },
          "offset": { "type": "integer", "minimum": 0 },
          "sites": { "type": "array", "items": { "$ref": "#/components/schemas/Site" } },
          "shelves": {
            "type": "object",
            "additionalProperties": false,
            "required": ["Plancton", "Corail", "Nautilus"],
            "properties": {
              "Plancton": { "$ref": "#/components/schemas/ShelfInfo" },
              "Corail": { "$ref": "#/components/schemas/ShelfInfo" },
              "Nautilus": { "$ref": "#/components/schemas/ShelfInfo" }
            }
          }
        }
      },
      "SiteResponse": { "type": "object", "additionalProperties": false, "required": ["ok", "site"], "properties": { "ok": { "type": "boolean", "const": true }, "site": { "$ref": "#/components/schemas/Site" } } },
      "RankQuery": { "type": "object", "additionalProperties": false, "required": ["query", "position", "clicks", "impressions"], "properties": { "query": { "type": "string" }, "position": { "type": "number", "minimum": 0 }, "clicks": { "type": "integer", "minimum": 0 }, "impressions": { "type": "integer", "minimum": 0 } } },
      "Article": {
        "type": "object",
        "additionalProperties": true,
        "required": ["id", "site_id", "top_queries", "state"],
        "properties": {
          "id": { "type": "integer", "minimum": 1 },
          "site_id": { "type": "integer", "minimum": 1 },
          "domain": { "type": ["string", "null"] },
          "slug": { "type": ["string", "null"] },
          "url": { "type": ["string", "null"], "format": "uri" },
          "title": { "type": ["string", "null"] },
          "top_queries": { "type": "array", "items": { "$ref": "#/components/schemas/RankQuery" } },
          "gsc_top_position": { "type": ["number", "null"], "minimum": 0 },
          "gsc_total_impressions": { "type": ["integer", "null"], "minimum": 0 },
          "state": { "type": "string", "enum": ["available", "reserved", "sold"] }
        }
      },
      "ArticlesResponse": { "type": "object", "additionalProperties": false, "required": ["ok", "site_id", "count", "articles"], "properties": { "ok": { "type": "boolean", "const": true }, "site_id": { "type": "integer", "minimum": 1 }, "count": { "type": "integer", "minimum": 0 }, "articles": { "type": "array", "items": { "$ref": "#/components/schemas/Article" } } } },
      "BalanceResponse": { "type": "object", "additionalProperties": false, "required": ["ok", "balance_cents", "balance_eur"], "properties": { "ok": { "type": "boolean", "const": true }, "balance_cents": { "type": "integer", "minimum": 0 }, "balance_eur": { "type": "number", "minimum": 0 } } },
      "OrderSummary": { "type": "object", "additionalProperties": false, "required": ["id", "status", "total_eur", "created_at", "items_count"], "properties": { "id": { "type": "string" }, "status": { "type": "string" }, "total_eur": { "type": "number", "minimum": 0 }, "created_at": { "type": "string" }, "items_count": { "type": "integer", "minimum": 0 } } },
      "OrderListResponse": { "type": "object", "additionalProperties": false, "required": ["ok", "count", "orders"], "properties": { "ok": { "type": "boolean", "const": true }, "count": { "type": "integer", "minimum": 0 }, "orders": { "type": "array", "items": { "$ref": "#/components/schemas/OrderSummary" } } } },
      "AnchorType": { "type": "string", "enum": ["exact", "partial", "branded", "generic", "naked"] },
      "LinkFormat": { "type": "string", "enum": ["article_unitaire", "lien_insere"] },
      "OrderItemInput": {
        "type": "object",
        "additionalProperties": false,
        "required": ["site_id", "target_url", "anchor_text"],
        "properties": {
          "site_id": { "type": "integer", "minimum": 1 },
          "target_url": { "type": "string", "format": "uri", "maxLength": 500 },
          "anchor_text": { "type": "string", "minLength": 1, "maxLength": 200 },
          "anchor_type": { "$ref": "#/components/schemas/AnchorType" },
          "content_brief": { "type": ["string", "null"], "maxLength": 2000 },
          "format": { "$ref": "#/components/schemas/LinkFormat" },
          "article_id": { "type": ["integer", "null"], "minimum": 1, "description": "Required when format is lien_insere." },
          "tier2_pack_size": { "type": "integer", "enum": [0, 1, 3, 5], "default": 0 },
          "project_id": { "type": ["integer", "null"], "minimum": 1 }
        }
      },
      "CreateOrderRequest": { "type": "object", "additionalProperties": false, "required": ["items"], "properties": { "items": { "type": "array", "minItems": 1, "maxItems": 20, "items": { "$ref": "#/components/schemas/OrderItemInput" } }, "promo_code": { "type": "string", "maxLength": 80 }, "sandbox_credit_cents": { "type": "integer", "minimum": 0, "description": "Sandbox keys only: simulated prepaid balance used to test payment branches." } } },
      "Amounts": { "type": "object", "additionalProperties": false, "required": ["gross_cents", "discount_cents", "net_cents", "credit_cents", "card_cents"], "properties": { "gross_cents": { "type": "integer", "minimum": 0 }, "discount_cents": { "type": "integer", "minimum": 0 }, "net_cents": { "type": "integer", "minimum": 0 }, "credit_cents": { "type": "integer", "minimum": 0 }, "card_cents": { "type": "integer", "minimum": 0 } } },
      "CreateOrderResponse": {
        "type": "object",
        "additionalProperties": true,
        "required": ["ok", "order_status", "payment_url", "items_count", "amounts"],
        "properties": {
          "ok": { "type": "boolean", "const": true },
          "sandbox": { "type": "boolean", "default": false },
          "quote_id": { "type": ["string", "null"] },
          "order_id": { "type": ["string", "null"] },
          "order_status": { "type": "string" },
          "payment_url": { "type": ["string", "null"], "format": "uri", "description": "A human must open this URL when non-null." },
          "items_count": { "type": "integer", "minimum": 1, "maximum": 20 },
          "would_require_human_payment": { "type": "boolean" },
          "applied_discount_code": { "type": ["string", "null"] },
          "gross_total_eur": { "type": "number", "minimum": 0 },
          "total_eur": { "type": "number", "minimum": 0 },
          "discount_eur": { "type": "number", "minimum": 0 },
          "credit_applied_cents": { "type": "integer", "minimum": 0 },
          "card_amount_cents": { "type": "integer", "minimum": 0 },
          "amounts": { "$ref": "#/components/schemas/Amounts" }
        }
      },
      "OrderItem": { "type": "object", "additionalProperties": false, "required": ["site_domain", "format", "status", "anchor_text", "target_url", "published_url", "article_id", "tier2_count", "project_id"], "properties": { "site_domain": { "type": "string" }, "format": { "$ref": "#/components/schemas/LinkFormat" }, "status": { "type": "string", "enum": ["to_assign", "assigned", "drafted", "in_review", "approved", "published", "verified", "cancelled", "replaced"] }, "anchor_text": { "type": "string" }, "target_url": { "type": "string", "format": "uri" }, "published_url": { "type": ["string", "null"], "format": "uri" }, "article_id": { "type": ["integer", "null"] }, "tier2_count": { "type": "integer", "minimum": 0 }, "project_id": { "type": ["integer", "null"] } } },
      "Order": { "type": "object", "additionalProperties": false, "required": ["id", "status", "total_eur", "created_at", "items"], "properties": { "id": { "type": "string" }, "status": { "type": "string" }, "total_eur": { "type": "number", "minimum": 0 }, "created_at": { "type": "string" }, "items": { "type": "array", "items": { "$ref": "#/components/schemas/OrderItem" } } } },
      "OrderResponse": { "type": "object", "additionalProperties": false, "required": ["ok", "order"], "properties": { "ok": { "type": "boolean", "const": true }, "order": { "$ref": "#/components/schemas/Order" } } },
      "QuoteResponse": { "type": "object", "additionalProperties": false, "required": ["ok", "quote_id", "status", "gross_total_eur", "total_eur", "discount_eur", "credit_applied_cents", "card_amount_cents", "amounts", "created_at", "items_count", "order_id", "order_status"], "properties": { "ok": { "type": "boolean", "const": true }, "quote_id": { "type": "string" }, "status": { "type": "string" }, "gross_total_eur": { "type": "number", "minimum": 0 }, "total_eur": { "type": "number", "minimum": 0 }, "discount_eur": { "type": "number", "minimum": 0 }, "applied_discount_code": { "type": ["string", "null"] }, "credit_applied_cents": { "type": "integer", "minimum": 0 }, "card_amount_cents": { "type": "integer", "minimum": 0 }, "amounts": { "$ref": "#/components/schemas/Amounts" }, "created_at": { "type": "string" }, "items_count": { "type": "integer", "minimum": 0 }, "order_id": { "type": ["string", "null"] }, "order_status": { "type": ["string", "null"] } } },
      "WebhookEvent": { "type": "string", "enum": ["order.accepted", "order.published", "order.cancelled"] },
      "Webhook": { "type": "object", "additionalProperties": false, "required": ["id", "url", "events", "created_at", "revoked_at", "last_triggered_at", "last_status", "last_error"], "properties": { "id": { "type": "string" }, "url": { "type": "string", "format": "uri" }, "events": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookEvent" } }, "created_at": { "type": "string" }, "revoked_at": { "type": ["string", "null"] }, "last_triggered_at": { "type": ["string", "null"] }, "last_status": { "type": ["integer", "null"] }, "last_error": { "type": ["string", "null"] } } },
      "WebhookListResponse": { "type": "object", "additionalProperties": false, "required": ["ok", "count", "webhooks"], "properties": { "ok": { "type": "boolean", "const": true }, "count": { "type": "integer", "minimum": 0 }, "webhooks": { "type": "array", "items": { "$ref": "#/components/schemas/Webhook" } } } },
      "CreateWebhookRequest": { "type": "object", "additionalProperties": false, "required": ["url", "events"], "properties": { "url": { "type": "string", "format": "uri", "maxLength": 2000, "description": "Public HTTPS URL; private, loopback, and unresolved hosts are rejected." }, "events": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/components/schemas/WebhookEvent" } } } },
      "CreateWebhookResponse": { "type": "object", "additionalProperties": false, "required": ["ok", "id", "url", "events", "secret", "signing_key_derivation", "created_at"], "properties": { "ok": { "type": "boolean", "const": true }, "id": { "type": "string" }, "url": { "type": "string", "format": "uri" }, "events": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookEvent" } }, "secret": { "type": "string", "description": "One-time secret; store it immediately." }, "signing_key_derivation": { "type": "string", "const": "hex(sha256(secret))" }, "created_at": { "type": "string" } } },
      "Project": { "type": "object", "additionalProperties": false, "required": ["id", "domain", "label", "theme"], "properties": { "id": { "type": "integer", "minimum": 1 }, "domain": { "type": "string" }, "label": { "type": ["string", "null"] }, "theme": { "type": ["string", "null"] } } },
      "ProjectListResponse": { "type": "object", "additionalProperties": false, "required": ["ok", "count", "projects"], "properties": { "ok": { "type": "boolean", "const": true }, "count": { "type": "integer", "minimum": 0 }, "projects": { "type": "array", "items": { "$ref": "#/components/schemas/Project" } } } },
      "PlanItem": { "allOf": [{ "$ref": "#/components/schemas/OrderItemInput" }, { "type": "object", "required": ["format", "anchor_type", "project_id", "tier2_pack_size"] }] },
      "PlanResponse": { "type": "object", "additionalProperties": false, "required": ["ok", "project", "gaps_count", "items"], "properties": { "ok": { "type": "boolean", "const": true }, "project": { "$ref": "#/components/schemas/Project" }, "gaps_count": { "type": "integer", "minimum": 0 }, "items": { "type": "array", "items": { "$ref": "#/components/schemas/PlanItem" } } } }
    }
  }
}
