{
  "openapi": "3.1.0",
  "info": {
    "title": "Clickwise Publisher API",
    "version": "1.1",
    "description": "One publisher API key for products, programs, tracking links, conversions, reports, clicks and conversion postbacks. Every response carries RateLimit-* and X-Request-Id headers; errors share one shape. Changes inside v1 are additive; a breaking change ships as a new version, announced in advance through Deprecation and Sunset headers. The same capabilities are available to AI agents through the MCP server at https://partners.clickwise.net/api/v1/mcp and to HasOffers-compatible tools at https://partners.clickwise.net/Apiv3/json.",
    "contact": {
      "name": "Clickwise integrations",
      "email": "partnerships@clickwise.net"
    }
  },
  "servers": [
    {
      "url": "https://partners.clickwise.net/api/v1/publisher"
    }
  ],
  "security": [
    {
      "ApiKeyHeader": []
    },
    {
      "BearerKey": []
    }
  ],
  "tags": [
    {
      "name": "Account"
    },
    {
      "name": "Products"
    },
    {
      "name": "Programs"
    },
    {
      "name": "Links"
    },
    {
      "name": "Reporting"
    },
    {
      "name": "Postbacks"
    }
  ],
  "paths": {
    "/me/": {
      "get": {
        "operationId": "getMe",
        "summary": "Who am I: account, access and limits",
        "tags": [
          "Account"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/products/": {
      "get": {
        "operationId": "searchProducts",
        "summary": "Search GTIN products with your tracked links",
        "tags": [
          "Products"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 200
            },
            "description": "Phrase in the title."
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[A-Z]{2}$"
            },
            "description": "ISO alpha-2 market (UK = GB)."
          },
          {
            "name": "merchant",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Merchant id from merchant.id."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "description": "Page size."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000,
              "default": 0
            },
            "description": "Follow next_offset."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          }
        }
      }
    },
    "/products/lookup/": {
      "get": {
        "operationId": "lookupProducts",
        "summary": "Refresh price and stock by id and/or GTIN (1-100)",
        "tags": [
          "Products"
        ],
        "parameters": [
          {
            "name": "ids",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated product ids."
          },
          {
            "name": "gtins",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated GTINs (checksums validated)."
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ISO alpha-2 market."
          },
          {
            "name": "merchant",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Merchant id."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "description": "Page size."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            },
            "description": "Follow next_offset."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          }
        }
      }
    },
    "/programs/": {
      "get": {
        "operationId": "listPrograms",
        "summary": "Programs you may promote (and, optionally, can apply to)",
        "tags": [
          "Programs"
        ],
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Name filter."
          },
          {
            "name": "include_available",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Also list programs open for application."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number."
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 50
            },
            "description": "Rows per page."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Page"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Program"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          }
        }
      }
    },
    "/programs/joinable/": {
      "get": {
        "operationId": "listJoinablePrograms",
        "summary": "Programs open for application",
        "tags": [
          "Programs"
        ],
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Name filter."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number."
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Rows per page."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Page"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Program"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          }
        }
      }
    },
    "/programs/apply/": {
      "post": {
        "operationId": "applyToProgram",
        "summary": "Apply to a program (approved or pending review)",
        "tags": [
          "Programs"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Replays the first response for 24 h when retried with the same body; a different body under the same key is 409."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "program_id": {
                    "type": "integer"
                  },
                  "campaign_id": {
                    "type": [
                      "string",
                      "integer"
                    ]
                  }
                }
              },
              "example": {
                "program_id": 123
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "201": {
            "description": "Approved",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          }
        }
      }
    },
    "/links/": {
      "get": {
        "operationId": "listLinks",
        "summary": "Your tracking links",
        "tags": [
          "Links"
        ],
        "parameters": [
          {
            "name": "subid",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Exact sub-ID."
          },
          {
            "name": "campaign_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Campaign id."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number."
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Rows per page."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Page"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Link"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          }
        }
      },
      "post": {
        "operationId": "createLink",
        "summary": "Create or return one tracking link",
        "tags": [
          "Links"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Replays the first response for 24 h when retried with the same body; a different body under the same key is 409."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LinkRequest"
              },
              "example": {
                "campaign_id": 123,
                "subid": "homepage_banner",
                "landing_url": "https://merchant.example/p/1"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Existing link",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Link"
                }
              }
            }
          },
          "201": {
            "description": "Created",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Link"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          }
        }
      }
    },
    "/links/batch/": {
      "post": {
        "operationId": "createLinksBatch",
        "summary": "Create up to 50 links; each item reports its own status",
        "tags": [
          "Links"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Replays the first response for 24 h when retried with the same body; a different body under the same key is 409."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "links"
                ],
                "properties": {
                  "links": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 50,
                    "items": {
                      "$ref": "#/components/schemas/LinkRequest"
                    }
                  }
                }
              },
              "example": {
                "links": [
                  {
                    "campaign_id": 123,
                    "subid": "post_1"
                  },
                  {
                    "program_id": 456,
                    "subid": "post_2"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LinkBatchResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          }
        }
      }
    },
    "/conversions/": {
      "get": {
        "operationId": "listConversions",
        "summary": "Your conversions with a sub-ID rollup",
        "tags": [
          "Reporting"
        ],
        "parameters": [
          {
            "name": "date_from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive start (YYYY-MM-DD)."
          },
          {
            "name": "date_to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive end (YYYY-MM-DD)."
          },
          {
            "name": "subid",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Exact sub-ID."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "declined"
              ]
            },
            "description": "Status."
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "v1",
                "ledger"
              ]
            },
            "description": "Data plane."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number."
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 500
            },
            "description": "Rows per page."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Page"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Conversion"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          }
        }
      }
    },
    "/reports/": {
      "get": {
        "operationId": "getReport",
        "summary": "Conversions and commission grouped (time series or dimension)",
        "tags": [
          "Reporting"
        ],
        "parameters": [
          {
            "name": "group_by",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "day",
                "week",
                "month",
                "subid",
                "campaign",
                "status"
              ],
              "default": "day"
            },
            "description": "Grouping; time groups are dense."
          },
          {
            "name": "date_from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive start (YYYY-MM-DD)."
          },
          {
            "name": "date_to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive end (YYYY-MM-DD)."
          },
          {
            "name": "subid",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Exact sub-ID."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "declined"
              ]
            },
            "description": "Status."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Report"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          }
        }
      }
    },
    "/clicks/": {
      "get": {
        "operationId": "listClicks",
        "summary": "Your clicks on Clickwise redirects",
        "tags": [
          "Reporting"
        ],
        "parameters": [
          {
            "name": "sub_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Exact sub-ID."
          },
          {
            "name": "campaign_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Campaign."
          },
          {
            "name": "deeplink_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Link id."
          },
          {
            "name": "include_bots",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Include filtered bot clicks."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number."
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200
            },
            "description": "Rows per page."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          }
        }
      }
    },
    "/postback/": {
      "get": {
        "operationId": "getPostback",
        "summary": "Conversion postback (webhook) configuration",
        "tags": [
          "Postbacks"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostbackConfig"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          }
        }
      },
      "put": {
        "operationId": "setPostback",
        "summary": "Not available with an API key: set the postback URL in the portal",
        "description": "Always 403 `postback_write_requires_portal` with a publisher key, so a leaked key cannot redirect your conversions. Use the portal (Settings > Postback) or the portal API token.",
        "tags": [
          "Postbacks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "https URL with {macro} placeholders."
                  },
                  "http_method": {
                    "type": "string",
                    "enum": [
                      "GET",
                      "POST"
                    ]
                  },
                  "event_types": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "active": {
                    "type": "boolean"
                  }
                }
              },
              "example": {
                "url": "https://tracker.example/pb?sub={subid}&amount={commission}&status={status}",
                "http_method": "GET"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostbackConfig"
                }
              }
            }
          },
          "201": {
            "description": "Created; the only response with the secret",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostbackConfig"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          }
        }
      }
    },
    "/postback/secret/": {
      "post": {
        "operationId": "rotatePostbackSecret",
        "summary": "Not available with an API key: rotate the secret in the portal",
        "description": "Always 403 `postback_write_requires_portal` with a publisher key.",
        "tags": [
          "Postbacks"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      }
    },
    "/postback/test/": {
      "post": {
        "operationId": "testPostback",
        "summary": "Send a signed test event",
        "tags": [
          "Postbacks"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      }
    },
    "/postback/deliveries/": {
      "get": {
        "operationId": "listPostbackDeliveries",
        "summary": "Recent postback delivery attempts",
        "tags": [
          "Postbacks"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "503": {
            "$ref": "#/components/responses/E503"
          }
        }
      }
    }
  },
  "webhooks": {
    "saleEvent": {
      "post": {
        "summary": "Conversion postback sent to your URL",
        "description": "Events sale.created, sale.approved, sale.declined, sale.reversed. Signature: hex(HMAC-SHA256(secret, \"<X-CW-Timestamp>.\" + message)); message = the full URL (GET) or the raw JSON body (POST). Retries with exponential backoff (up to 8 attempts, capped at 6 h).",
        "parameters": [
          {
            "name": "X-CW-Event",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-CW-Delivery",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-CW-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-CW-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaleEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      },
      "BearerKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "The same publisher API key."
      }
    },
    "headers": {
      "RateLimit-Limit": {
        "schema": {
          "type": "integer"
        },
        "description": "Requests allowed per window."
      },
      "RateLimit-Remaining": {
        "schema": {
          "type": "integer"
        },
        "description": "Requests left in this window."
      },
      "RateLimit-Reset": {
        "schema": {
          "type": "integer"
        },
        "description": "Seconds until the window resets."
      },
      "RateLimit-Policy": {
        "schema": {
          "type": "string"
        },
        "description": "For example 120;w=60."
      },
      "X-Request-Id": {
        "schema": {
          "type": "string"
        },
        "description": "Echoes a valid X-Request-Id, else generated."
      },
      "Retry-After": {
        "schema": {
          "type": "integer"
        },
        "description": "Seconds to wait."
      }
    },
    "responses": {
      "E400": {
        "description": "Invalid request",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E401": {
        "description": "Missing or invalid key",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E403": {
        "description": "Not allowed for this key or account",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E404": {
        "description": "Not found for this account",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E409": {
        "description": "Idempotency-Key reused with a different body",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E429": {
        "description": "Rate limit; wait Retry-After seconds",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E503": {
        "description": "Temporary dependency failure; retry with backoff",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "detail",
          "error"
        ],
        "properties": {
          "detail": {
            "description": "Human-readable message (kept for existing clients)."
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "status",
              "request_id"
            ],
            "properties": {
              "code": {
                "type": "string",
                "examples": [
                  "not_authenticated",
                  "throttled",
                  "invalid_request",
                  "api_key_scope",
                  "idempotency_key_reused"
                ]
              },
              "message": {
                "type": "string"
              },
              "status": {
                "type": "integer"
              },
              "request_id": {
                "type": "string",
                "description": "Also sent as X-Request-Id."
              }
            }
          }
        }
      },
      "Me": {
        "type": "object",
        "properties": {
          "affiliate": {
            "type": "object",
            "properties": {
              "ref": {
                "type": "string"
              },
              "status": {
                "type": "string"
              }
            }
          },
          "api_version": {
            "type": "string"
          },
          "access": {
            "type": "object",
            "additionalProperties": {
              "type": "boolean"
            }
          },
          "rate_limits": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          }
        }
      },
      "Product": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "gtin": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "price": {
            "type": "string",
            "description": "Decimal string in currency."
          },
          "currency": {
            "type": "string"
          },
          "image": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Clickwise link tracked to the caller."
          },
          "merchant": {
            "type": "object",
            "properties": {
              "id": {
                "type": "integer"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "availability": {
            "type": "string",
            "enum": [
              "in_stock",
              "out_of_stock",
              "preorder",
              "backorder"
            ]
          },
          "country": {
            "type": "string"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ProductPage": {
        "type": "object",
        "properties": {
          "products": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Product"
            }
          },
          "count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "next_offset": {
            "type": [
              "integer",
              "null"
            ]
          },
          "freshness_hours": {
            "type": "integer"
          }
        }
      },
      "Program": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Clickwise campaign id (links, reports)."
          },
          "campaign_id": {
            "type": "string"
          },
          "campaign_name": {
            "type": "string"
          },
          "landing_url": {
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "link_ready": {
            "type": "boolean"
          },
          "link_ready_error": {
            "type": [
              "string",
              "null"
            ]
          },
          "existing_links": {
            "type": "integer"
          },
          "assignment_status": {
            "type": "string",
            "enum": [
              "assigned",
              "not_assigned"
            ]
          },
          "can_apply": {
            "type": "boolean"
          },
          "commission": {
            "type": "object",
            "description": "What this publisher earns.",
            "properties": {
              "rate": {
                "type": "string"
              },
              "type": {
                "type": "string"
              },
              "source": {
                "type": "string",
                "enum": [
                  "campaign_payout",
                  "program_listing"
                ]
              }
            }
          },
          "program": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "Page": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer"
          },
          "page": {
            "type": "integer"
          },
          "page_size": {
            "type": "integer"
          },
          "pages": {
            "type": "integer"
          }
        }
      },
      "Link": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "created": {
            "type": "boolean"
          },
          "deeplink_id": {
            "type": "string"
          },
          "cw_link": {
            "type": "string",
            "format": "uri",
            "description": "The link to publish."
          },
          "destination_link": {
            "type": "string"
          },
          "subid": {
            "type": "string"
          },
          "certified_tracking_link": {
            "type": "string"
          }
        }
      },
      "LinkRequest": {
        "type": "object",
        "properties": {
          "campaign_id": {
            "type": [
              "string",
              "integer"
            ]
          },
          "program_id": {
            "type": "integer"
          },
          "subid": {
            "type": "string",
            "maxLength": 100
          },
          "landing_url": {
            "type": "string",
            "description": "A page on the merchant's own domain."
          }
        }
      },
      "LinkBatchResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "index": {
                  "type": "integer"
                },
                "status": {
                  "type": "integer"
                },
                "link": {
                  "$ref": "#/components/schemas/Link"
                },
                "error": {
                  "$ref": "#/components/schemas/Error/properties/error"
                }
              }
            }
          },
          "created": {
            "type": "integer"
          },
          "existing": {
            "type": "integer"
          },
          "failed": {
            "type": "integer"
          }
        }
      },
      "Conversion": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string"
          },
          "transaction_id": {
            "type": "string"
          },
          "occurred_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "campaign_id": {},
          "subid": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "declined"
            ]
          },
          "commission": {
            "type": "number",
            "description": "What this publisher earns."
          },
          "sale_amount": {
            "type": [
              "number",
              "null"
            ]
          },
          "currency": {
            "type": "string"
          }
        }
      },
      "ReportRow": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "conversions": {
            "type": "integer"
          },
          "pending": {
            "type": "integer"
          },
          "approved": {
            "type": "integer"
          },
          "declined": {
            "type": "integer"
          },
          "commission_by_currency": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            },
            "description": "Amounts per ISO currency code."
          },
          "approved_commission_by_currency": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            },
            "description": "Amounts per ISO currency code."
          },
          "commission_usd": {
            "type": "number"
          },
          "approved_commission_usd": {
            "type": "number"
          },
          "unconverted": {
            "type": "integer",
            "description": "Rows without a USD rate (not in *_usd)."
          }
        }
      },
      "Report": {
        "type": "object",
        "properties": {
          "group_by": {
            "type": "string"
          },
          "date_from": {
            "type": "string"
          },
          "date_to": {
            "type": "string"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReportRow"
            }
          },
          "totals": {
            "$ref": "#/components/schemas/ReportRow"
          },
          "truncated": {
            "type": "boolean"
          }
        }
      },
      "PostbackConfig": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "configured": {
            "type": "boolean"
          },
          "url": {
            "type": "string"
          },
          "http_method": {
            "type": "string",
            "enum": [
              "GET",
              "POST"
            ]
          },
          "event_types": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "active": {
            "type": "boolean"
          },
          "macros": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "SaleEvent": {
        "type": "object",
        "description": "POST body (GET postbacks receive the same values as macros).",
        "properties": {
          "event": {
            "type": [
              "string",
              "number",
              "null"
            ]
          },
          "subid": {
            "type": [
              "string",
              "number",
              "null"
            ]
          },
          "click_id": {
            "type": [
              "string",
              "number",
              "null"
            ]
          },
          "transaction_id": {
            "type": [
              "string",
              "number",
              "null"
            ]
          },
          "order_ref": {
            "type": [
              "string",
              "number",
              "null"
            ]
          },
          "sale_amount": {
            "type": [
              "string",
              "number",
              "null"
            ]
          },
          "commission": {
            "type": [
              "string",
              "number",
              "null"
            ]
          },
          "currency": {
            "type": [
              "string",
              "number",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "number",
              "null"
            ]
          },
          "campaign_id": {
            "type": [
              "string",
              "number",
              "null"
            ]
          }
        }
      }
    }
  }
}