{
  "openapi": "3.1.0",
  "info": {
    "title": "BuyPost Customer API",
    "version": "1.7.0",
    "description": "Read the BuyPost price list, submit sponsored-article orders and track them from your own system.\n\nScope: read (price list, balance, orders, articles), submit new orders, and — exactly where the site allows it — approve an article, request a fix, cancel, or change details. Orders are created UNPAID; the purchase is completed by the customer on https://ai.buypost.co.il/UnpaidOrders (credits or card). Payment, buying credits and webhook settings are site-only.\n\nAll requests are POST to one endpoint with a JSON body that contains `action`. Authenticate with `Authorization: Bearer bp_live_...` (keys are created by approved customers on https://ai.buypost.co.il/ApiAccess). Amounts are ILS before VAT unless a field says incl_vat. Every response is `{ok: true, data}` or `{ok: false, error: {code, message, hint?, details?}}` — `hint` says what to do. Limits: 10 requests per minute and 300 requests per day per ACCOUNT (all keys together; BuyPost can raise it per customer). Every request counts. Responses carry `meta.requests_left_today` and the header X-RateLimit-Remaining-Day.\n\nStay inside them without polling: receive webhooks (article.* , order.paid, credits.added), read several articles in one call with get_items, and ask list_items only for what changed with `updated_since` (= the `checked_at` of your previous call). Read answers may be served from a short cache (`meta.cached`, `meta.fresh_for_seconds`); any write of yours, any article status change and any credit purchase refreshes it at once.\n\nBought but not used yet: `list_redeemable` returns the credits balance, articles that were bought and paid but not redeemed yet (redeem each with `redeem`), orders waiting for payment and how many the balance covers, and a recommendation to buy credits when it does not.\n\nHuman docs: https://ai.buypost.co.il/ApiDocs . Plain-text guide for AI agents: https://ai.buypost.co.il/customer-api.txt",
    "contact": {
      "name": "BuyPost support",
      "url": "https://ai.buypost.co.il/SupportTickets"
    }
  },
  "servers": [
    {
      "url": "https://ai.buypost.co.il/functions"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/customerApi": {
      "post": {
        "operationId": "customerApi",
        "summary": "Single endpoint — choose the operation with `action`",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/PingRequest"
                  },
                  {
                    "$ref": "#/components/schemas/BalanceRequest"
                  },
                  {
                    "$ref": "#/components/schemas/PriceListRequest"
                  },
                  {
                    "$ref": "#/components/schemas/QuoteRequest"
                  },
                  {
                    "$ref": "#/components/schemas/CreateOrderRequest"
                  },
                  {
                    "$ref": "#/components/schemas/GetOrderRequest"
                  },
                  {
                    "$ref": "#/components/schemas/ListItemsRequest"
                  },
                  {
                    "$ref": "#/components/schemas/GetItemRequest"
                  },
                  {
                    "$ref": "#/components/schemas/ApproveRequest"
                  },
                  {
                    "$ref": "#/components/schemas/RequestFixRequest"
                  },
                  {
                    "$ref": "#/components/schemas/CancelRequest"
                  },
                  {
                    "$ref": "#/components/schemas/UpdateItemRequest"
                  },
                  {
                    "$ref": "#/components/schemas/GetItemsRequest"
                  },
                  {
                    "$ref": "#/components/schemas/ListRedeemableRequest"
                  },
                  {
                    "$ref": "#/components/schemas/SubmitEditRequest"
                  },
                  {
                    "$ref": "#/components/schemas/ReplaceFileRequest"
                  },
                  {
                    "$ref": "#/components/schemas/RejectContentRequest"
                  },
                  {
                    "$ref": "#/components/schemas/ListOrdersRequest"
                  },
                  {
                    "$ref": "#/components/schemas/AiFixRequest"
                  }
                ],
                "discriminator": {
                  "propertyName": "action"
                }
              },
              "examples": {
                "price_list": {
                  "value": {
                    "action": "price_list",
                    "search": "news",
                    "max_price": 800,
                    "limit": 50
                  }
                },
                "create_order": {
                  "value": {
                    "action": "create_order",
                    "idempotency_key": "crm-order-10457",
                    "items": [
                      {
                        "website_id": "WEBSITE_ID",
                        "content": {
                          "type": "ai"
                        },
                        "article_topic": "How to choose a wedding photographer",
                        "writing_style": "seo_with_brand",
                        "brand_name": "Studio Or",
                        "keywords": "wedding photography",
                        "target_link": "https://example.co.il/weddings"
                      }
                    ]
                  }
                },
                "list_items": {
                  "value": {
                    "action": "list_items",
                    "waiting_for_you": true,
                    "limit": 50
                  }
                },
                "get_items": {
                  "value": {
                    "action": "get_items",
                    "item_ids": [
                      "ITEM_ID_1",
                      "ITEM_ID_2"
                    ]
                  }
                },
                "changes_since": {
                  "value": {
                    "action": "list_items",
                    "updated_since": "2026-10-02T08:00:00Z"
                  }
                },
                "list_redeemable": {
                  "value": {
                    "action": "list_redeemable"
                  }
                },
                "redeem": {
                  "value": {
                    "action": "redeem",
                    "item_id": "ITEM_ID",
                    "changes": {
                      "article_topic": "How to choose a wedding photographer",
                      "keywords": "wedding photography",
                      "target_link": "https://example.co.il/weddings",
                      "writing_style": "professional",
                      "scheduled_date": "2026-11-01"
                    }
                  }
                },
                "redeem_later": {
                  "value": {
                    "action": "create_order",
                    "idempotency_key": "crm-future-77",
                    "items": [
                      {
                        "website_id": "WEBSITE_ID",
                        "redeem_later": true,
                        "quantity": 3
                      }
                    ]
                  }
                },
                "images_and_shared": {
                  "value": {
                    "action": "quote",
                    "items": [
                      {
                        "website_id": "WEBSITE_ID",
                        "content": {
                          "type": "ai"
                        },
                        "article_topic": "How to choose a wedding photographer",
                        "writing_style": "professional",
                        "keywords": "wedding photography",
                        "target_link": "https://example.co.il/weddings",
                        "shared_with": "Studio Or Ltd",
                        "image": {
                          "option": "upload",
                          "images": [
                            {
                              "url": "https://cdn.example.co.il/a.jpg",
                              "credit": "Studio Or"
                            }
                          ]
                        }
                      }
                    ]
                  }
                },
                "reject_content": {
                  "value": {
                    "action": "reject_content",
                    "item_id": "ITEM_ID",
                    "reason": "The tone does not fit our brand — more formal, no superlatives"
                  }
                },
                "list_orders": {
                  "value": {
                    "action": "list_orders",
                    "payment_status": "paid",
                    "created_from": "2026-09-01",
                    "limit": 20
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "500": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "webhooks": {
    "articleEvent": {
      "post": {
        "summary": "Article status changed, an API order was paid, or credits were added (configured on https://ai.buypost.co.il/ApiAccess)",
        "description": "Headers: X-BuyPost-Event, X-BuyPost-Timestamp, X-BuyPost-Signature = 'sha256=' + hex(HMAC_SHA256(secret, timestamp + '.' + raw_body)). Reject if the timestamp is older than 5 minutes or the signature does not match. Answer 2xx within 5 seconds.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "bp_live_... key. Send it only from a server."
      }
    },
    "responses": {
      "Error": {
        "description": "Error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "PingRequest": {
        "type": "object",
        "required": [
          "action"
        ],
        "properties": {
          "action": {
            "const": "ping"
          }
        }
      },
      "BalanceRequest": {
        "type": "object",
        "required": [
          "action"
        ],
        "properties": {
          "action": {
            "const": "balance"
          }
        },
        "description": "Credits balance (ILS before VAT), who pays (own/agency account), the account limits, and `redeemable`: {prepaid_articles, orders_waiting_for_payment, waiting_total_before_vat, covered_by_credits} plus `recommendation` (null or {reason, suggested_credits_before_vat, buy_credits_url, message}). Details: list_redeemable. Also articles_waiting_for_your_approval (count)."
      },
      "PriceListRequest": {
        "type": "object",
        "required": [
          "action"
        ],
        "description": "Read-only price list with this customer's price (sale, special price and fixed discount applied). Cache it on your side — the list changes rarely. `websites` is an alias. Each website also says what its order form requires: writing_notes, publishing_restrictions, single_link_only, website_type (seo_only), requires_shared_fields, requires_image_approval, pixel_option + pixel_price_before_vat; and why the price is what it is: price_source (sale / special_price / list_price) and fixed_discount_percent.",
        "properties": {
          "action": {
            "enum": [
              "price_list",
              "websites"
            ]
          },
          "search": {
            "type": "string",
            "description": "Matches name or URL"
          },
          "category": {
            "type": "string"
          },
          "max_price": {
            "type": "number"
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 500,
            "default": 100
          },
          "offset": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          },
          "region": {
            "type": "string",
            "description": "Filter by region (as the website card shows it)"
          },
          "city": {
            "type": "string",
            "description": "Filter by city (local news websites)"
          },
          "language": {
            "type": "string"
          },
          "min_dr": {
            "type": "number",
            "description": "Only websites with DR at least this"
          },
          "tier": {
            "type": "string",
            "enum": [
              "regular",
              "advanced",
              "premium"
            ]
          },
          "feature": {
            "type": "string",
            "description": "One feature from `features`, e.g. dofollow"
          },
          "on_sale": {
            "type": "boolean",
            "description": "true = only websites on sale"
          },
          "instant_publishing": {
            "type": "boolean",
            "description": "true = only websites that publish instantly"
          },
          "sort": {
            "type": "string",
            "enum": [
              "price_asc",
              "price_desc",
              "dr_desc"
            ],
            "description": "Default: the site catalogue order"
          }
        }
      },
      "OrderItem": {
        "type": "object",
        "required": [
          "website_id"
        ],
        "properties": {
          "website_id": {
            "type": "string",
            "description": "id from price_list"
          },
          "content": {
            "type": "object",
            "description": "ai = BuyPost writes it; html = your ready article (>=300 text chars, no script/iframe/event handlers); docx = Word file as base64 (<=8MB).",
            "properties": {
              "type": {
                "enum": [
                  "ai",
                  "html",
                  "docx"
                ],
                "default": "ai"
              },
              "html": {
                "type": "string"
              },
              "filename": {
                "type": "string",
                "description": "for docx: *.docx or *.doc"
              },
              "file_base64": {
                "type": "string"
              }
            }
          },
          "article_topic": {
            "type": "string",
            "description": "Required for content.type=ai, at least 3 words"
          },
          "writing_style": {
            "enum": [
              "professional",
              "marketing",
              "seo_no_brand",
              "seo_with_brand",
              "ai_engines"
            ],
            "description": "Required for ai. seo_with_brand needs brand_name. SEO-only websites accept only seo_no_brand."
          },
          "brand_name": {
            "type": "string"
          },
          "target_audience": {
            "type": "string"
          },
          "keywords": {
            "type": "string",
            "description": "One keyword, no commas. Required for ai; optional for html/docx (then together with target_link)"
          },
          "target_link": {
            "type": "string",
            "format": "uri"
          },
          "keywords_2": {
            "type": "string",
            "description": "Only together with target_link_2; not on single-link websites"
          },
          "target_link_2": {
            "type": "string",
            "format": "uri"
          },
          "scheduled_date": {
            "type": "string",
            "format": "date",
            "description": "YYYY-MM-DD, not in the past, Sunday–Thursday (no Friday/Saturday, like the site). The article stays a regular one that waits for the team's topic approval."
          },
          "image": {
            "type": "object",
            "description": "auto_select (default) — BuyPost picks; stock — a link to an image (url; customer_url is an older name for it); upload — your own images: 1–2 items, each a public https url OR file_base64+filename (jpg/png/webp ≤5MB, stored once), and a photo credit for each (required).",
            "properties": {
              "option": {
                "enum": [
                  "auto_select",
                  "stock",
                  "customer_url",
                  "upload"
                ]
              },
              "url": {
                "type": "string",
                "format": "uri"
              },
              "images": {
                "type": "array",
                "minItems": 1,
                "maxItems": 2,
                "items": {
                  "type": "object",
                  "required": [
                    "credit"
                  ],
                  "properties": {
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "file_base64": {
                      "type": "string"
                    },
                    "filename": {
                      "type": "string"
                    },
                    "credit": {
                      "type": "string",
                      "description": "Photo credit, e.g. יח\"צ / photographer / business name"
                    }
                  }
                }
              }
            }
          },
          "client_label": {
            "type": "string",
            "description": "Your end-client name (agencies)"
          },
          "notes": {
            "type": "string",
            "description": "Notes for the BuyPost team"
          },
          "shared_with": {
            "type": "string",
            "description": "\"בשיתוף עם\" — who the article is published together with. Required when the website has requires_shared_fields (see price_list)."
          },
          "shared_company_id": {
            "type": "string",
            "description": "Company number (ח.פ) of the shared partner — optional"
          },
          "team_notes": {
            "type": "string",
            "description": "Notes for the BuyPost team only (not for the writer)"
          },
          "pixel": {
            "type": "object",
            "description": "A tracking pixel — only on websites with pixel_option free/paid (see price_list); a paid pixel adds pixel_price_before_vat to the article price. Send url (https) or file_base64+filename (≤5MB).",
            "properties": {
              "url": {
                "type": "string",
                "format": "uri"
              },
              "file_base64": {
                "type": "string"
              },
              "filename": {
                "type": "string"
              }
            }
          },
          "redeem_later": {
            "type": "boolean",
            "description": "Buy now, redeem later (\"מימוש עתידי\", like the site): only website_id (and quantity, client_label, notes, team_notes). After payment the article waits for redemption (awaiting_redemption) — send its details with redeem."
          },
          "quantity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 20,
            "description": "With redeem_later: how many articles of this website (counts toward the 20-article order limit)"
          }
        },
        "description": "One article. Required: website_id; for content.type=ai also article_topic (3+ words), writing_style, keywords and target_link; for a ready article (html/docx) keywords+target_link are optional but always together; shared_with where the website has requires_shared_fields. redeem_later=true buys now and takes NO details (redeem them after payment)."
      },
      "QuoteRequest": {
        "type": "object",
        "required": [
          "action",
          "items"
        ],
        "description": "Validate and price without creating anything. Lines carry list_price, price, charged_price, price_source (sale/special_price/list_price), fixed_discount_percent, pixel_price, and website_rules (writing_notes, publishing_restrictions, single_link_only, seo_only, requires_shared_fields, requires_image_approval) — the AI writer follows these rules. Coupons: returns coupons[] ({id, source, type, code, website_id, lines, discount}) and coupon_discount_before_vat; lines carry coupon_discount.",
        "properties": {
          "action": {
            "const": "quote"
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/OrderItem"
            }
          },
          "coupon_code": {
            "type": "string",
            "description": "Use this coupon code (general or personal). Without it the customer's own coupons apply automatically."
          },
          "apply_coupons": {
            "type": "boolean",
            "default": true,
            "description": "false = apply no automatic coupon (a coupon_code still applies)"
          }
        }
      },
      "CreateOrderRequest": {
        "type": "object",
        "required": [
          "action",
          "idempotency_key",
          "items"
        ],
        "description": "Submit an order. It is created UNPAID (status draft) — nothing is charged. The customer pays on https://ai.buypost.co.il/UnpaidOrders; payment moves the articles into work. Reusing an idempotency_key returns the original order (replayed=true). Coupons are applied like in quote and consumed only when the order is paid; order.coupons / order.coupon_discount_before_vat show them.",
        "properties": {
          "action": {
            "const": "create_order"
          },
          "idempotency_key": {
            "type": "string",
            "minLength": 8,
            "maxLength": 100
          },
          "notes": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/OrderItem"
            }
          },
          "coupon_code": {
            "type": "string",
            "description": "Use this coupon code (general or personal). Without it the customer's own coupons apply automatically."
          },
          "apply_coupons": {
            "type": "boolean",
            "default": true,
            "description": "false = apply no automatic coupon (a coupon_code still applies)"
          }
        }
      },
      "GetOrderRequest": {
        "type": "object",
        "required": [
          "action",
          "order_id"
        ],
        "properties": {
          "action": {
            "const": "get_order"
          },
          "order_id": {
            "type": "string"
          }
        }
      },
      "ListItemsRequest": {
        "type": "object",
        "required": [
          "action"
        ],
        "description": "The account's articles, newest first. Returns {total, limit, offset, checked_at, items}.",
        "properties": {
          "action": {
            "const": "list_items"
          },
          "status": {
            "type": "string",
            "description": "Article status filter, e.g. published"
          },
          "order_id": {
            "type": "string"
          },
          "waiting_for_you": {
            "type": "boolean",
            "description": "Articles waiting for the customer: in review (act through the API — see available_actions) or a website draft (approved on the BuyPost site)"
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          },
          "offset": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          },
          "updated_since": {
            "type": "string",
            "format": "date-time",
            "description": "Only articles changed after this moment. Pass the checked_at of your previous list_items call."
          },
          "awaiting_redemption": {
            "type": "boolean",
            "description": "Only articles that were bought and paid but not redeemed yet (redeem them with redeem)."
          },
          "created_from": {
            "type": "string",
            "format": "date"
          },
          "created_to": {
            "type": "string",
            "format": "date"
          }
        }
      },
      "GetItemRequest": {
        "type": "object",
        "required": [
          "action",
          "item_id"
        ],
        "description": "One article; includes content_html once the article reached the customer.",
        "properties": {
          "action": {
            "const": "get_item"
          },
          "item_id": {
            "type": "string"
          }
        }
      },
      "Payment": {
        "type": "object",
        "properties": {
          "status": {
            "enum": [
              "awaiting_payment",
              "paid",
              "cancelled"
            ]
          },
          "total_before_vat": {
            "type": [
              "number",
              "null"
            ]
          },
          "total_incl_vat": {
            "type": [
              "number",
              "null"
            ]
          },
          "pay_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where the customer completes the purchase"
          }
        }
      },
      "Article": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "order_id": {
            "type": "string"
          },
          "website": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "url": {
                "type": "string"
              }
            }
          },
          "status": {
            "enum": [
              "pending",
              "topic_approved",
              "writing",
              "admin_review",
              "review",
              "approved",
              "awaiting_image_approval",
              "image_approved",
              "sent_to_publisher",
              "publisher_draft_review",
              "resubmitted_to_publisher",
              "draft_review",
              "published",
              "rejected"
            ]
          },
          "payment_status": {
            "enum": [
              "awaiting_payment",
              "paid",
              "cancelled",
              null
            ]
          },
          "waiting_for_you": {
            "type": "boolean"
          },
          "article_topic": {
            "type": [
              "string",
              "null"
            ]
          },
          "keywords": {
            "type": [
              "string",
              "null"
            ]
          },
          "target_link": {
            "type": [
              "string",
              "null"
            ]
          },
          "publishing_type": {
            "enum": [
              "immediate",
              "future",
              null
            ]
          },
          "scheduled_date": {
            "type": [
              "string",
              "null"
            ]
          },
          "published_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "draft_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "rejection_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "price_before_vat": {
            "type": [
              "number",
              "null"
            ]
          },
          "stages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string"
                },
                "at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          },
          "content_html": {
            "type": "string",
            "description": "Only in get_item, once the article reached the customer"
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "awaiting_redemption": {
            "type": "boolean",
            "description": "Bought and paid, not redeemed yet — redeem it with redeem."
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "progress": {
            "type": "object",
            "description": "Where the article is, in words",
            "properties": {
              "stage": {
                "enum": [
                  "awaiting_payment",
                  "awaiting_redemption",
                  "topic_returned",
                  "details_missing",
                  "topic_review",
                  "writing",
                  "team_review",
                  "waiting_for_your_approval",
                  "image_approval",
                  "preparing_to_send",
                  "at_website",
                  "website_draft_for_you",
                  "published",
                  "cancelled"
                ]
              },
              "label": {
                "type": "string",
                "description": "Hebrew"
              },
              "waiting_on": {
                "enum": [
                  "customer",
                  "team",
                  "website",
                  "payment",
                  null
                ]
              },
              "next_step": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Hebrew — what to do next (when it waits on you)"
              },
              "published_url": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "available_actions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "API actions that fit the article's stage now, e.g. approve, request_fix, submit_edit, replace_file, reject_content, redeem, update_item, update_item:scheduled_date, cancel"
          },
          "warnings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Warning"
            }
          }
        }
      },
      "Success": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "data": {
            "type": "object",
            "description": "Action result. create_order: {order, items: Article[], payment: Payment, replayed, message}. list_items: {total, limit, offset, items: Article[]}. price_list: {total, websites: [{id, name, url, category, list_price_before_vat, on_sale, price_before_vat, ...}]}. get_items/list_items also return checked_at. list_redeemable: see ListRedeemableRequest. balance: + redeemable, recommendation."
          },
          "meta": {
            "type": "object",
            "properties": {
              "cached": {
                "type": "boolean",
                "description": "The answer came from the short read cache"
              },
              "fresh_for_seconds": {
                "type": "integer",
                "description": "How long this answer stays cached (read actions)"
              },
              "requests_left_today": {
                "type": "integer",
                "description": "Requests left today for the account"
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "ok": {
            "const": false
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "enum": [
                  "missing_or_malformed_key",
                  "invalid_key",
                  "api_not_enabled",
                  "rate_limited",
                  "daily_request_limit",
                  "too_many_bad_keys",
                  "invalid_json",
                  "unknown_action",
                  "site_only",
                  "method_not_allowed",
                  "items_missing",
                  "too_many_items",
                  "validation_failed",
                  "idempotency_key_required",
                  "billing_profile_incomplete",
                  "too_many_unpaid_orders",
                  "daily_article_limit",
                  "order_failed",
                  "file_upload_failed",
                  "order_id_missing",
                  "order_not_found",
                  "item_id_missing",
                  "item_not_found",
                  "internal_error",
                  "not_waiting_for_approval",
                  "note_required",
                  "not_cancellable",
                  "already_cancelled",
                  "not_editable",
                  "field_not_editable",
                  "changes_missing",
                  "scheduled_date_invalid",
                  "insufficient_credits",
                  "busy_try_again",
                  "item_ids_missing",
                  "too_many_item_ids",
                  "invalid_updated_since",
                  "order_not_paid",
                  "order_not_payable",
                  "order_empty",
                  "payer_not_found",
                  "redeem_details_required",
                  "webhook_url_invalid",
                  "redeem_after_payment",
                  "redeem_later_no_details",
                  "reason_required",
                  "scheduled_date_weekend",
                  "coupon_not_found",
                  "coupon_unusable",
                  "coupon_invalid",
                  "coupon_not_combinable",
                  "coupon_min_order",
                  "coupon_not_applicable",
                  "coupon_changed",
                  "invalid_date",
                  "invalid_payment_status",
                  "invalid_source",
                  "instructions_required",
                  "ai_fix_limit",
                  "ai_fix_failed",
                  "no_text_to_fix",
                  "article_changed",
                  "edit_save_failed"
                ]
              },
              "message": {
                "type": "string",
                "description": "Hebrew, human readable"
              },
              "hint": {
                "type": "string",
                "description": "What to do next"
              },
              "details": {
                "description": "validation_failed: [{index (order line, 0-based), website_id, errors: [{code, field, message}]}] — field is the request field to fix; message is Hebrew. error.message already lists the problems per article."
              }
            }
          }
        }
      },
      "WebhookEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "enum": [
              "article.waiting_for_approval",
              "article.published",
              "article.rejected",
              "article.status_changed",
              "ping",
              "order.paid",
              "credits.added"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "type": "object",
            "properties": {
              "item": {
                "$ref": "#/components/schemas/Article"
              },
              "previous_status": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "description": "article.*: {item, previous_status}. order.paid: {order_id, order_number, payment_method: credits|card, articles_activated}. credits.added: {credits_added_before_vat, balance_before_vat} — call list_redeemable next."
          }
        }
      },
      "ApproveRequest": {
        "type": "object",
        "required": [
          "action",
          "item_id"
        ],
        "description": "Approve an article waiting for the customer (status review). Same as the site.",
        "properties": {
          "action": {
            "const": "approve"
          },
          "item_id": {
            "type": "string"
          }
        }
      },
      "RequestFixRequest": {
        "type": "object",
        "required": [
          "action",
          "item_id",
          "note"
        ],
        "description": "Ask the BuyPost team for a fix on an article waiting for approval.",
        "properties": {
          "action": {
            "const": "request_fix"
          },
          "item_id": {
            "type": "string"
          },
          "note": {
            "type": "string",
            "minLength": 5
          }
        }
      },
      "CancelRequest": {
        "type": "object",
        "required": [
          "action",
          "item_id"
        ],
        "description": "Cancel an article where the site allows it: before writing starts (pending/topic_approved) or in review after the team asked for a fix. Articles of an unpaid order can always be cancelled (the amount due drops). Refunds for paid articles go to credits per the terms. Otherwise 409 not_cancellable.",
        "properties": {
          "action": {
            "const": "cancel"
          },
          "item_id": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        }
      },
      "UpdateItemRequest": {
        "type": "object",
        "required": [
          "action",
          "item_id",
          "changes"
        ],
        "description": "Change details where the site allows it: any brief field while the API order is unpaid (an article of an unpaid or cancelled SITE order → 409 order_not_paid); scheduled_date (null = ASAP) before the article is sent to the website; brief fields when the team sent the topic back. `redeem` (alias): an article that was bought and PAID but not redeemed yet (list_redeemable / awaiting_redemption) — send article_topic, keywords, target_link, writing_style (and optionally scheduled_date); the article enters work (redeemed: true). a date alone on an unredeemed article → 409 redeem_details_required. Website and price never change. Otherwise 409 not_editable.",
        "properties": {
          "action": {
            "enum": [
              "update_item",
              "redeem"
            ]
          },
          "item_id": {
            "type": "string"
          },
          "changes": {
            "type": "object",
            "properties": {
              "article_topic": {
                "type": "string"
              },
              "keywords": {
                "type": "string"
              },
              "target_link": {
                "type": "string"
              },
              "keywords_2": {
                "type": "string"
              },
              "target_link_2": {
                "type": "string"
              },
              "writing_style": {
                "type": "string"
              },
              "brand_name": {
                "type": "string"
              },
              "target_audience": {
                "type": "string"
              },
              "notes": {
                "type": "string"
              },
              "client_label": {
                "type": "string"
              },
              "image": {
                "type": "object"
              },
              "scheduled_date": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date"
              },
              "shared_with": {
                "type": "string"
              },
              "shared_company_id": {
                "type": "string"
              },
              "team_notes": {
                "type": "string"
              }
            }
          }
        }
      },
      "GetItemsRequest": {
        "type": "object",
        "required": [
          "action",
          "item_ids"
        ],
        "description": "Several articles in ONE request (up to 50) — use it instead of many get_item calls. Returns {total, checked_at, items}. Ids of other accounts are silently left out.",
        "properties": {
          "action": {
            "const": "get_items"
          },
          "item_ids": {
            "type": "array",
            "minItems": 1,
            "maxItems": 50,
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ListRedeemableRequest": {
        "type": "object",
        "required": [
          "action"
        ],
        "description": "What the account bought and can use now: {credits:{balance_before_vat, paid_by, recent_activity[]}, prepaid_articles:{redeemable_count, by_website[{website, count, item_ids}], items[{item_id, order_id, order_number, website, price_before_vat, purchased_at, scheduled_date}], awaiting_payment[], how_to_redeem}, waiting_for_payment:{orders[{order_id, order_number, source: api|site, total_before_vat, total_incl_vat}], total_before_vat, covered_by_credits, coverage_is_estimate, pay_url}, waiting_for_your_approval:{count, items[{item_id, website, status}]}, recommendation, next_steps[] (Hebrew)}. `redeemable` is an alias.",
        "properties": {
          "action": {
            "enum": [
              "list_redeemable",
              "redeemable"
            ]
          }
        }
      },
      "SubmitEditRequest": {
        "type": "object",
        "required": [
          "action",
          "item_id",
          "content_html"
        ],
        "description": "Article waiting for your approval (review): send your corrected text (HTML, 300+ characters, no script). The team checks it before it goes to the website — like \"עריכה ישירה\" on the site.",
        "properties": {
          "action": {
            "const": "submit_edit"
          },
          "item_id": {
            "type": "string"
          },
          "content_html": {
            "type": "string"
          },
          "note": {
            "type": "string"
          },
          "keep_for_review": {
            "type": "boolean",
            "default": false,
            "description": "true = save and keep the article with you (status review); approve later sends it to the team check"
          }
        }
      },
      "ReplaceFileRequest": {
        "type": "object",
        "required": [
          "action",
          "item_id",
          "filename",
          "file_base64"
        ],
        "description": "Article waiting for your approval: replace it with your own Word file (.docx/.doc ≤8MB) — like \"החלפה בקובץ\".",
        "properties": {
          "action": {
            "const": "replace_file"
          },
          "item_id": {
            "type": "string"
          },
          "filename": {
            "type": "string"
          },
          "file_base64": {
            "type": "string"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "RejectContentRequest": {
        "type": "object",
        "required": [
          "action",
          "item_id",
          "reason"
        ],
        "description": "Reject the written article (review): it goes back to the team to be written again, with your reason (5+ characters). The new text returns for your approval. To cancel the article itself use cancel, where allowed.",
        "properties": {
          "action": {
            "const": "reject_content"
          },
          "item_id": {
            "type": "string"
          },
          "reason": {
            "type": "string",
            "minLength": 5
          }
        }
      },
      "Website": {
        "type": "object",
        "description": "One website in price_list — everything the site catalogue shows, with THIS customer's price. The price_list answer also has general_restrictions (text shown on the site under every website).",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          },
          "language": {
            "type": [
              "string",
              "null"
            ]
          },
          "region": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "website_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "dr": {
            "type": [
              "number",
              "null"
            ]
          },
          "ur": {
            "type": [
              "number",
              "null"
            ]
          },
          "turnaround_days": {
            "type": [
              "number",
              "null"
            ]
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "public_notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "tier_badge": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "regular",
              "advanced",
              "premium",
              null
            ]
          },
          "features": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "instant_publishing": {
            "type": "boolean",
            "description": "Published instantly after approval (no publisher queue)"
          },
          "example_articles": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                }
              }
            }
          },
          "content_tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "recommended_topics": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "single_link_only": {
            "type": "boolean"
          },
          "publishing_restrictions": {
            "type": [
              "string",
              "null"
            ]
          },
          "writing_notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "requires_shared_fields": {
            "type": "boolean"
          },
          "requires_image_approval": {
            "type": "boolean"
          },
          "image_approval_text": {
            "type": [
              "string",
              "null"
            ]
          },
          "requires_publisher_draft": {
            "type": "boolean",
            "description": "The website sends a draft for approval before the final publication"
          },
          "pixel_option": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "free",
              "paid",
              null
            ]
          },
          "pixel_price_before_vat": {
            "type": [
              "number",
              "null"
            ]
          },
          "list_price_before_vat": {
            "type": [
              "number",
              "null"
            ]
          },
          "on_sale": {
            "type": "boolean"
          },
          "sale_price_before_vat": {
            "type": [
              "number",
              "null"
            ]
          },
          "price_before_vat": {
            "type": "number",
            "description": "Your price, before VAT"
          },
          "price_source": {
            "type": "string",
            "enum": [
              "sale",
              "special_price",
              "list_price"
            ]
          },
          "fixed_discount_percent": {
            "type": "number"
          }
        }
      },
      "ListOrdersRequest": {
        "type": "object",
        "required": [
          "action"
        ],
        "description": "Past and current orders (site and API) with payment state and where every article is. Each order: order fields + source, articles_count, published_count, waiting_for_you_count, stages {stage: count}, articles [{id, website_name, status, stage, label, waiting_on, waiting_for_you, published_url}].",
        "properties": {
          "action": {
            "type": "string",
            "const": "list_orders"
          },
          "payment_status": {
            "type": "string",
            "enum": [
              "paid",
              "awaiting_payment",
              "cancelled"
            ]
          },
          "source": {
            "type": "string",
            "enum": [
              "api",
              "site"
            ]
          },
          "created_from": {
            "type": "string",
            "format": "date"
          },
          "created_to": {
            "type": "string",
            "format": "date"
          },
          "search": {
            "type": "string",
            "description": "Part of the order number"
          },
          "updated_since": {
            "type": "string",
            "format": "date-time",
            "description": "Pass checked_at from the previous answer to get only changed orders"
          },
          "limit": {
            "type": "integer",
            "maximum": 100,
            "default": 50
          },
          "offset": {
            "type": "integer",
            "default": 0
          }
        }
      },
      "AiFixRequest": {
        "type": "object",
        "required": [
          "action",
          "item_id",
          "instructions"
        ],
        "description": "The AI rewrites the article (status review) by your instructions and returns content_html; the article stays with you. Max 5 per article, 20 per 24 hours. Answer: {item_id, status, content_html, ai_fixes_left_for_article, ai_fixes_left_today, message}.",
        "properties": {
          "action": {
            "type": "string",
            "const": "ai_fix"
          },
          "item_id": {
            "type": "string"
          },
          "instructions": {
            "type": "string",
            "minLength": 5,
            "maxLength": 2000
          }
        }
      },
      "Warning": {
        "type": "object",
        "description": "Non-blocking warning. no_external_link = a ready article without any link (any web address, the publishing website included, or mailto: / tel: counts).",
        "properties": {
          "index": {
            "type": "integer",
            "description": "Item index in the request (quote / create_order)"
          },
          "code": {
            "type": "string",
            "enum": [
              "no_external_link"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Connecting an AI tool or agent (Claude Code, ChatGPT, Cursor, n8n/Make) — access steps and rules",
    "url": "https://ai.buypost.co.il/ApiAiGuide"
  }
}
