{
  "openapi": "3.1.0",
  "info": {
    "title": "Post Coverage Sandbox API",
    "version": "0.10.0",
    "description": "Synthetic orders only. No live insurance, charges or payouts, and no customer names, emails, phone numbers, street addresses or payment details: opaque references only, plus an order's products as items (since 0.10.0). Order access codes are returned once; securely persist the initial response. Retrying an externalId returns the same order without the private code."
  },
  "servers": [
    {
      "url": "https://3feo7wip5b.execute-api.us-east-1.amazonaws.com"
    }
  ],
  "paths": {
    "/integrations/v1/quotes": {
      "post": {
        "summary": "Create an illustrative sandbox quote",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "feeCents",
                    "pricingVersion",
                    "currency",
                    "environment",
                    "expiresIn",
                    "notice"
                  ],
                  "properties": {
                    "feeCents": {
                      "type": "integer",
                      "minimum": 0,
                      "description": "Protection fee in integer USD cents for this amountCents."
                    },
                    "pricingVersion": {
                      "type": "string",
                      "description": "Send with order creation. A changed configuration returns 409 there."
                    },
                    "currency": {
                      "const": "USD"
                    },
                    "environment": {
                      "const": "sandbox"
                    },
                    "expiresIn": {
                      "type": "integer",
                      "description": "Seconds the quote should be shown before re-quoting."
                    },
                    "notice": {
                      "type": "string"
                    },
                    "reward": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "description": "Preview of the store credit the order would earn if the customer selects protection, under the reward program as it stands at quote time. Null unless the company's reward program is active (sandbox_active), or when the amount would earn less than one cent. amountCents = floor(quote amountCents * rateBasisPoints / 10000), the same rule the reward ledger applies at order creation. Order creation reads the program again and does not check it against this quote, so a program saved (which returns it to draft), paused or re-rated in between changes or removes the award without an error. The earned reward is the one in GET /integrations/v1/orders/detail. It is store credit credited to the customer account, never a cash or card refund, and only orders with a customerKey earn it. Servers before 0.8.0 omit this field; treat a missing reward exactly like null.",
                      "required": [
                        "amountCents",
                        "rateBasisPoints",
                        "delayDays",
                        "expiryDays"
                      ],
                      "additionalProperties": false,
                      "properties": {
                        "amountCents": {
                          "type": "integer",
                          "minimum": 1
                        },
                        "rateBasisPoints": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 3000
                        },
                        "delayDays": {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 180,
                          "description": "Days after purchase before the credit is issued."
                        },
                        "expiryDays": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 365,
                          "description": "Days the issued credit stays usable."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant, or the checkout offer is switched off for this company. The switched-off answer carries \"code\": \"offer_disabled\": show no protection offer and ask again in a few minutes, never at once. For a valid amount it also carries \"currentPrice\" {feeCents, pricingVersion, currency}, the current price for checking an order that is already paid for; it is not an offer. Order creation and order events are never refused for this reason."
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "amountCents": {
                    "type": "integer",
                    "minimum": 100
                  },
                  "currency": {
                    "type": "string",
                    "enum": [
                      "USD"
                    ]
                  }
                },
                "required": [
                  "amountCents",
                  "currency"
                ]
              }
            }
          }
        },
        "description": "Quote the protection fee for the server-computed merchandise subtotal. The fee is computed here, never in the browser or the plugin. A company with no saved pricing uses the sandbox default: 3.5% of amountCents rounded up to a whole cent, minimum 99 cents, no maximum (pricingVersion \"sandbox-default-v2\"). Pass pricingVersion to order creation; a quote from an earlier configuration, including the retired 3% \"sandbox-default-v1\", returns 409 regardless of age. expiresIn is advisory and not enforced; re-quote before taking payment. A server before 0.8.0 still prices the default at 3% under \"sandbox-default-v1\" and omits reward, so always charge the returned feeCents and pass the returned pricingVersion rather than assuming either default."
      }
    },
    "/integrations/v1/orders": {
      "post": {
        "summary": "Create a sandbox order; externalId is idempotent per merchant",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Order, replayed flag, optional linked test policy, and accessCode (new opted-in order only; otherwise null). Persist the first code securely."
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "externalId": {
                    "type": "string",
                    "minLength": 4,
                    "maxLength": 80,
                    "pattern": "^[A-Za-z0-9_-]+$"
                  },
                  "amountCents": {
                    "type": "integer",
                    "minimum": 100
                  },
                  "currency": {
                    "type": "string",
                    "enum": [
                      "USD"
                    ]
                  },
                  "purchaseType": {
                    "type": "string",
                    "enum": [
                      "one_time",
                      "recurring"
                    ]
                  },
                  "customerOptedIn": {
                    "type": "boolean",
                    "description": "Explicit checkout choice. False records an unprotected order without a fee, policy, or access code."
                  },
                  "coverageEligible": {
                    "type": "boolean",
                    "default": true,
                    "description": "False requires customerOptedIn=false. When items are sent and none ships, the default is false and true is refused for an order without protection (digital items are not covered); an opted-in order with nothing to ship is recorded and flagged for staff. A list sent with itemsTruncated true decides none of this, since the cut may have left the shipped lines out."
                  },
                  "customerKey": {
                    "type": "string",
                    "minLength": 4,
                    "maxLength": 80,
                    "pattern": "^[A-Za-z0-9_-]+$",
                    "description": "Optional opaque merchant-scoped test customer identifier. Never send a name, email, phone number, address or payment details."
                  },
                  "deliveryStatus": {
                    "type": "string",
                    "enum": [
                      "processing",
                      "in_transit",
                      "delivered",
                      "exception"
                    ],
                    "default": "processing"
                  },
                  "pricingVersion": {
                    "type": "string",
                    "description": "Optional version from the quote. A changed configuration returns 409; request a fresh quote. The default changed from sandbox-default-v1 (3%) to sandbox-default-v2 (3.5%)."
                  },
                  "items": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 100,
                    "description": "Optional since 0.10.0: the order's products, descriptive only (amountCents stays the amount the fee was quoted on, which counts shippable items only). At most 32,000 bytes of compact UTF-8 JSON. Text may not contain control characters or bidi overrides. A replay with different items is a 409. An API before 0.10.0 answers 400 \"Unsupported fields.\" without creating anything; send the order again without items.",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "name",
                        "quantity",
                        "unitPriceCents",
                        "requiresShipping"
                      ],
                      "properties": {
                        "name": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "sku": {
                          "type": "string",
                          "maxLength": 100
                        },
                        "variant": {
                          "type": "string",
                          "maxLength": 120
                        },
                        "lineId": {
                          "type": "string",
                          "pattern": "^[A-Za-z0-9_.:-]{1,64}$"
                        },
                        "quantity": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 100000
                        },
                        "unitPriceCents": {
                          "type": "integer",
                          "minimum": 0
                        },
                        "requiresShipping": {
                          "type": "boolean",
                          "description": "False for a digital item: not covered and not in the fee base."
                        }
                      }
                    }
                  },
                  "itemsTruncated": {
                    "type": "boolean",
                    "default": false,
                    "description": "True when the store had more products than it sent."
                  }
                },
                "required": [
                  "externalId",
                  "amountCents",
                  "currency",
                  "purchaseType",
                  "customerOptedIn"
                ]
              }
            }
          }
        },
        "description": "Send every synthetic order, including declined and ineligible choices, for accurate observed reporting. Only eligible opted-in orders receive a test policy, illustrative fee, and private claim code. Rates are examples, not live commercial terms."
      }
    },
    "/integrations/v1/claims": {
      "get": {
        "summary": "List claims for the authenticated merchant",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "claims",
                    "page"
                  ],
                  "properties": {
                    "claims": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "lastCustomerVisibleUpdateAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "When the customer last had news on this claim: a support-team reply they can see, or a status change made by the support team. Null until the first. A store integration can use it to email its own customer a content-free \"your claim has an update\" notice with the private claim link. It is never a message: claim lists carry no message content. Absent on backends older than 2026-09-25."
                          }
                        }
                      }
                    },
                    "page": {
                      "type": "object",
                      "required": [
                        "nextCursor",
                        "complete",
                        "evaluatedRecords",
                        "readAt",
                        "consistency"
                      ],
                      "properties": {
                        "nextCursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "complete": {
                          "type": "boolean"
                        },
                        "evaluatedRecords": {
                          "type": "integer"
                        },
                        "readAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "consistency": {
                          "const": "current_records_not_snapshot"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "description": "Returns one bounded page, not all company records. Follow page.nextCursor unchanged until page.complete is true, even when a page has no visible rows. pageSize bounds evaluated records (1-100, default 100); DynamoDB may stop earlier at its byte limit. Cursor is bound to the authenticated company and collection. Reads are current records, not a point-in-time snapshot. Retry a failed page with the same cursor; never treat a failed or capped traversal as a complete total.",
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 4096
            },
            "description": "Opaque continuation position from the previous response."
          }
        ]
      }
    },
    "/public/claims": {
      "post": {
        "summary": "Report a sandbox issue with a private code",
        "security": [],
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "orderId": {
                    "type": "string",
                    "minLength": 5,
                    "maxLength": 60
                  },
                  "accessCode": {
                    "type": "string",
                    "minLength": 30,
                    "maxLength": 100,
                    "writeOnly": true
                  },
                  "reason": {
                    "type": "string",
                    "enum": [
                      "lost",
                      "damaged",
                      "stolen"
                    ]
                  },
                  "remedy": {
                    "type": "string",
                    "enum": [
                      "store_credit",
                      "refund",
                      "replace"
                    ],
                    "description": "Optional. The customer's choice: store credit (since 0.9.0), a refund or a replacement. Omit it when the customer made no choice; the claim then records not_stated. An API before 0.9.0 answers 400 \"Choose a supported remedy.\" to store_credit without saving anything; send the claim again without it."
                  },
                  "affectedItems": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 100,
                    "description": "Optional since 0.10.0: which shipped items were affected, by their index in the lookup's items, at most the quantity ordered. Omit it for the whole parcel. The lookup (POST /public/claims/lookup) lists the order's shipped items, without prices, as items.",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "index",
                        "quantity"
                      ],
                      "properties": {
                        "index": {
                          "type": "integer",
                          "minimum": 0
                        },
                        "quantity": {
                          "type": "integer",
                          "minimum": 1
                        }
                      }
                    }
                  }
                },
                "required": [
                  "orderId",
                  "accessCode",
                  "reason"
                ]
              }
            }
          }
        }
      }
    },
    "/public/claims/lookup": {
      "post": {
        "summary": "Check a sandbox report with a private code",
        "security": [],
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "orderId": {
                    "type": "string",
                    "minLength": 5,
                    "maxLength": 60
                  },
                  "accessCode": {
                    "type": "string",
                    "minLength": 30,
                    "maxLength": 100,
                    "writeOnly": true
                  }
                },
                "required": [
                  "orderId",
                  "accessCode"
                ]
              }
            }
          }
        },
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque continuation returned for this exact history section and authorization scope."
          },
          {
            "name": "section",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "messages",
                "status"
              ]
            },
            "description": "Required with cursor. Private access credentials stay in the JSON body, never in the URL."
          }
        ],
        "description": "Returns current claim, evidence and bounded customer-visible messages/status history. Inspect historyPages.messages and historyPages.status. A page containing only internal notes returns no messages with complete=false; continue normally. No internal note body or operator decision history is exposed. Continuations verify the current private access code each time."
      }
    },
    "/public/claims/messages": {
      "post": {
        "summary": "Add a synthetic customer reply using the private order code",
        "security": [],
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "orderId": {
                    "type": "string",
                    "minLength": 5,
                    "maxLength": 60
                  },
                  "accessCode": {
                    "type": "string",
                    "minLength": 30,
                    "maxLength": 100,
                    "writeOnly": true
                  },
                  "body": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2000
                  },
                  "requestId": {
                    "type": "string",
                    "minLength": 10,
                    "maxLength": 80,
                    "pattern": "^[A-Za-z0-9_-]+$"
                  },
                  "synthetic": {
                    "type": "boolean",
                    "const": true
                  }
                },
                "required": [
                  "orderId",
                  "accessCode",
                  "body",
                  "requestId",
                  "synthetic"
                ]
              }
            }
          }
        },
        "description": "Requires an existing open claim. Internal notes are never included. A reply to waiting_customer resumes review. No email is sent. Repeat the same requestId and body for safe retries."
      }
    },
    "/integrations/v1/orders/detail": {
      "get": {
        "summary": "Read an order, policy, reward, and event history",
        "description": "Events are bounded to one page. Continue with historyPages.events.nextCursor until complete. The order, policy and reward are current on every response. Old unpaged reads fail with 409 if history is incomplete. Mutations return a bounded initial history and are never reported as failed merely because more history exists.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success. Sandbox ledger changes only; no money or external credit moved."
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "parameters": [
          {
            "name": "orderId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{4,100}$"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque continuation returned for this exact history section and authorization scope."
          }
        ]
      }
    },
    "/integrations/v1/orders/events": {
      "post": {
        "summary": "Record an idempotent delivery, cancellation, or refund event",
        "description": "Refund amount is an incremental adjustment, required only for refunded events. fee_refunded (0.10.0) reports a refund of the protection fee: no amount for the whole fee, else feeRefundCents; once the whole fee is refunded, protection on the order ends, shipped or not, and a second fee_refunded answers 409 'Protection already ended on this order.'. Events use current order.version (null for old unversioned orders). Reuse requestId on retries. Reverse applied test credit before cancelling or refunding a redemption order. No refund is paid. The returned event history is bounded; use the detail route with historyPages.events.nextCursor to continue. The mutation outcome is independent of history completeness.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success. Sandbox ledger changes only; no money or external credit moved."
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "orderId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{4,100}$"
                  },
                  "type": {
                    "enum": [
                      "in_transit",
                      "delivered",
                      "exception",
                      "cancelled",
                      "refunded",
                      "fee_refunded"
                    ]
                  },
                  "requestId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{4,100}$"
                  },
                  "expectedVersion": {
                    "type": [
                      "integer",
                      "null"
                    ],
                    "minimum": 1
                  },
                  "refundAmountCents": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "feeRefundCents": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Optional, with fee_refunded only (0.10.0): the part of the protection fee refunded. Leave it out when the whole fee was refunded."
                  },
                  "synthetic": {
                    "const": true
                  },
                  "shipments": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 10,
                    "description": "Optional, with in_transit, delivered and exception events (0.9.0). The order's parcels. Post Coverage reads the carrier from the number when it is not given (USPS, UPS, FedEx, DHL, Amazon, OnTrac), builds each tracking link itself, and keeps up to 20 parcels per order. An event without shipments replays exactly as before.",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "trackingNumber"
                      ],
                      "properties": {
                        "trackingNumber": {
                          "type": "string",
                          "pattern": "^[A-Za-z0-9 -]{4,40}$"
                        },
                        "carrier": {
                          "type": "string",
                          "maxLength": 40,
                          "description": "The carrier's name, as the store knows it"
                        }
                      }
                    }
                  }
                },
                "required": [
                  "orderId",
                  "type",
                  "requestId",
                  "expectedVersion",
                  "synthetic"
                ]
              }
            }
          }
        }
      }
    },
    "/integrations/v1/rewards": {
      "get": {
        "summary": "List the company sandbox reward ledger",
        "description": "Returns one bounded page, not all company records. Follow page.nextCursor unchanged until page.complete is true, even when a page has no visible rows. pageSize bounds evaluated records (1-100, default 100); DynamoDB may stop earlier at its byte limit. Cursor is bound to the authenticated company and collection. Reads are current records, not a point-in-time snapshot. Retry a failed page with the same cursor; never treat a failed or capped traversal as a complete total.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success. Sandbox ledger changes only; no money or external credit moved.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "rewards",
                    "page"
                  ],
                  "properties": {
                    "rewards": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "page": {
                      "type": "object",
                      "required": [
                        "nextCursor",
                        "complete",
                        "evaluatedRecords",
                        "readAt",
                        "consistency"
                      ],
                      "properties": {
                        "nextCursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "complete": {
                          "type": "boolean"
                        },
                        "evaluatedRecords": {
                          "type": "integer"
                        },
                        "readAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "consistency": {
                          "const": "current_records_not_snapshot"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 4096
            },
            "description": "Opaque continuation position from the previous response."
          }
        ]
      }
    },
    "/integrations/v1/rewards/redeem": {
      "post": {
        "summary": "Apply synthetic credit to a subsequent order",
        "description": "Requires an issued, unexpired balance and a later order for the same opaque customerKey. Atomic version checks prevent overspending. This does not issue credit to WooCommerce or another merchant checkout.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success. Sandbox ledger changes only; no money or external credit moved."
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "rewardId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{4,100}$"
                  },
                  "orderId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{4,100}$"
                  },
                  "requestId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{4,100}$"
                  },
                  "amountCents": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "expectedVersion": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "synthetic": {
                    "const": true
                  }
                },
                "required": [
                  "rewardId",
                  "orderId",
                  "requestId",
                  "amountCents",
                  "expectedVersion",
                  "synthetic"
                ]
              }
            }
          }
        }
      }
    },
    "/integrations/v1/rewards/reverse": {
      "post": {
        "summary": "Reverse an applied test credit without extending its expiry",
        "description": "Idempotent by original redemption ID. Restores only still-eligible, unexpired credit. A source-order refund can reduce the restored amount.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success. Sandbox ledger changes only; no money or external credit moved."
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "redemptionId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{4,100}$"
                  },
                  "synthetic": {
                    "const": true
                  }
                },
                "required": [
                  "redemptionId",
                  "synthetic"
                ]
              }
            }
          }
        }
      }
    },
    "/public/claims/evidence/init": {
      "post": {
        "summary": "Initialize a synthetic private attachment",
        "security": [],
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          },
          "410": {
            "description": "Attachment access expired"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "orderId": {
                    "type": "string",
                    "minLength": 5,
                    "maxLength": 60
                  },
                  "accessCode": {
                    "type": "string",
                    "minLength": 30,
                    "maxLength": 100,
                    "writeOnly": true
                  },
                  "requestId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]+$"
                  },
                  "contentType": {
                    "enum": [
                      "image/png",
                      "image/jpeg",
                      "application/pdf"
                    ]
                  },
                  "sizeBytes": {
                    "type": "integer",
                    "minimum": 8,
                    "maximum": 5242880
                  },
                  "category": {
                    "enum": [
                      "outer_packaging",
                      "delivery_confirmation",
                      "other_test_evidence"
                    ]
                  },
                  "synthetic": {
                    "const": true
                  }
                },
                "required": [
                  "orderId",
                  "accessCode",
                  "requestId",
                  "contentType",
                  "sizeBytes",
                  "category",
                  "synthetic"
                ]
              }
            }
          }
        },
        "description": "Private claim code required. Synthetic test files only; no people, addresses, shipping labels, payment details or other personal data. Completed files are readable for seven days. Initialization returns a 5-minute presigned S3 POST with exact fields and file length; send the file last and then call complete within 15 minutes. At most 20 initiated uploads per case. Retries reuse requestId; accepted files pin an immutable S3 version. Original filenames are not accepted or stored. File signature validation is not malware scanning or personal-data screening."
      }
    },
    "/public/claims/evidence/complete": {
      "post": {
        "summary": "Finalize and pin the accepted object version",
        "security": [],
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          },
          "410": {
            "description": "Attachment access expired"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "orderId": {
                    "type": "string",
                    "minLength": 5,
                    "maxLength": 60
                  },
                  "accessCode": {
                    "type": "string",
                    "minLength": 30,
                    "maxLength": 100,
                    "writeOnly": true
                  },
                  "evidenceId": {
                    "type": "string"
                  },
                  "synthetic": {
                    "const": true
                  }
                },
                "required": [
                  "orderId",
                  "accessCode",
                  "evidenceId",
                  "synthetic"
                ]
              }
            }
          }
        },
        "description": "Private claim code required. Synthetic test files only; no people, addresses, shipping labels, payment details or other personal data. Completed files are readable for seven days. Initialization returns a 5-minute presigned S3 POST with exact fields and file length; send the file last and then call complete within 15 minutes. At most 20 initiated uploads per case. Retries reuse requestId; accepted files pin an immutable S3 version. Original filenames are not accepted or stored. File signature validation is not malware scanning or personal-data screening."
      }
    },
    "/public/claims/evidence/download": {
      "post": {
        "summary": "Create an attachment download link valid for up to two minutes",
        "security": [],
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          },
          "410": {
            "description": "Attachment access expired"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "orderId": {
                    "type": "string",
                    "minLength": 5,
                    "maxLength": 60
                  },
                  "accessCode": {
                    "type": "string",
                    "minLength": 30,
                    "maxLength": 100,
                    "writeOnly": true
                  },
                  "evidenceId": {
                    "type": "string"
                  }
                },
                "required": [
                  "orderId",
                  "accessCode",
                  "evidenceId"
                ]
              }
            }
          }
        },
        "description": "Private claim code required. Synthetic test files only; no people, addresses, shipping labels, payment details or other personal data. Completed files are readable for seven days. Initialization returns a 5-minute presigned S3 POST with exact fields and file length; send the file last and then call complete within 15 minutes. At most 20 initiated uploads per case. Retries reuse requestId; accepted files pin an immutable S3 version. Original filenames are not accepted or stored. File signature validation is not malware scanning or personal-data screening."
      }
    },
    "/integrations/v1/orders/claim-access": {
      "post": {
        "summary": "Reset a protected order private claim link and revoke all previous codes",
        "description": "Synthetic sandbox only. Requires current order version, unique requestId and explicit synthetic confirmation. The new accessCode is returned once. A replay returns accessCode null and does not rotate again. Old codes immediately fail API authorization; pre-existing signed file download links retain their original short expiration. No email is sent. The returned event history is bounded; use the detail route with historyPages.events.nextCursor to continue. The mutation outcome is independent of history completeness.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success. Sandbox ledger changes only; no money or external credit moved."
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Invalid order and private code pair"
          },
          "409": {
            "description": "Conflicting or concurrent write; refresh and retry"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "orderId",
                  "requestId",
                  "expectedVersion",
                  "synthetic"
                ],
                "properties": {
                  "orderId": {
                    "type": "string"
                  },
                  "requestId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{4,100}$"
                  },
                  "expectedVersion": {
                    "type": [
                      "integer",
                      "null"
                    ],
                    "minimum": 1
                  },
                  "synthetic": {
                    "const": true
                  }
                }
              }
            }
          }
        }
      }
    },
    "/integrations/v1/credits/check": {
      "post": {
        "summary": "Read the store credit a customer entered at checkout",
        "description": "Store credit Post Coverage funds, issued on a claim (2026-09-26). Answers {credit: {id, orderId, claimId, amountCents, balanceCents, redeemedCents, currency, codeLast4, funding, createdAt, lastUsedAt, simulated, status: active | spent | voided}}. Changes nothing. A code is spendable only at the store whose claim issued it; any other code answers 404.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The credit, never its code"
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "This store credit code was not found at this store (unknown, another store's, or malformed)"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "code": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64,
                    "description": "What the customer entered: PC-XXXX-XXXX-XXXX-XXXX in any case, with or without spaces, hyphens or the PC- prefix. O, I and L read as 0, 1, 1."
                  }
                },
                "required": [
                  "code"
                ]
              }
            }
          }
        }
      }
    },
    "/integrations/v1/credits/redeem": {
      "post": {
        "summary": "Spend store credit on an order as it is placed",
        "description": "Brings the balance down by amountCents in one conditional write, so two checkouts never spend the same dollars. Idempotent on requestId: the same redemption again answers the first with replayed: true; a different one under a used requestId is 409. Answers {credit, redemption: {id, creditId, amountCents, orderReference, status, createdAt, reversedAt}, replayed}.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Applied (sandbox; Post Coverage makes the discount good on the store's statement)"
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "This store credit code was not found at this store (unknown, another store's, or malformed)"
          },
          "409": {
            "description": "Not enough left, withdrawn, a requestId reused for a different redemption, or a concurrent write"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "code": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64,
                    "description": "What the customer entered: PC-XXXX-XXXX-XXXX-XXXX in any case, with or without spaces, hyphens or the PC- prefix. O, I and L read as 0, 1, 1."
                  },
                  "amountCents": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "orderReference": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9][A-Za-z0-9_.#/-]{0,63}$",
                    "description": "The store's own order number"
                  },
                  "requestId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{4,100}$"
                  },
                  "synthetic": {
                    "const": true
                  }
                },
                "required": [
                  "code",
                  "amountCents",
                  "orderReference",
                  "requestId",
                  "synthetic"
                ]
              }
            }
          }
        }
      }
    },
    "/integrations/v1/credits/reverse": {
      "post": {
        "summary": "Give a store credit redemption back in full",
        "description": "When the order it paid towards failed, was cancelled or was refunded. redemptionId is the redeem call's requestId. Idempotent: reversing again answers replayed: true. There are no partial reversals.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Reversed"
          },
          "400": {
            "description": "Invalid payload or unsupported fields"
          },
          "401": {
            "description": "Missing or revoked API key"
          },
          "403": {
            "description": "Paused merchant"
          },
          "404": {
            "description": "Redemption not found"
          },
          "409": {
            "description": "Not enough left, withdrawn, a requestId reused for a different redemption, or a concurrent write"
          },
          "429": {
            "description": "Rate limit"
          },
          "503": {
            "description": "Service unavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "redemptionId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{4,100}$"
                  },
                  "synthetic": {
                    "const": true
                  }
                },
                "required": [
                  "redemptionId",
                  "synthetic"
                ]
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      }
    }
  }
}
