{
  "openapi": "3.1.0",
  "info": {
    "title": "Moonetix Publisher API",
    "version": "1.1.0",
    "description": "List offers for your users, create sessions for the mobile SDKs, pull your statistics, and receive results through postbacks. Full guide: https://docs.moonetix.com",
    "contact": {
      "name": "Moonetix partners",
      "email": "partners@moonetix.com",
      "url": "https://docs.moonetix.com"
    },
    "termsOfService": "https://moonetix.com/terms"
  },
  "servers": [
    {
      "url": "https://api.moonetix.com"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "paths": {
    "/v1/offers": {
      "get": {
        "operationId": "listOffers",
        "summary": "List offers for a user",
        "description": "Returns the offers one user can start now, filtered for their country, device, and history. Send users to each offer's start_url. Limit: 600 requests per minute per app.",
        "parameters": [
          {
            "name": "user_id",
            "in": "query",
            "required": true,
            "description": "Your ID for the user, the same as in offerwall links and postbacks.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._@:+\\-]{1,100}$"
            },
            "example": "user_1234"
          },
          {
            "name": "country",
            "in": "query",
            "required": true,
            "description": "Two-letter ISO 3166-1 code of the user's country.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z]{2}$"
            },
            "example": "US"
          },
          {
            "name": "device",
            "in": "query",
            "required": false,
            "description": "The user's device. Send device or ua.",
            "schema": {
              "type": "string",
              "enum": [
                "desktop",
                "android",
                "ios"
              ]
            }
          },
          {
            "name": "ua",
            "in": "query",
            "required": false,
            "description": "The user agent of the user's browser. We read the device from it, so you can send it instead of device.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "sub1",
            "in": "query",
            "required": false,
            "description": "Your own tracking value, returned as {sub1} in postbacks and added to every start_url.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$"
            }
          },
          {
            "name": "sub2",
            "in": "query",
            "required": false,
            "description": "Your own tracking value, returned as {sub2} in postbacks and added to every start_url.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$"
            }
          },
          {
            "name": "sub3",
            "in": "query",
            "required": false,
            "description": "Your own tracking value, returned as {sub3} in postbacks and added to every start_url.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$"
            }
          },
          {
            "name": "sub4",
            "in": "query",
            "required": false,
            "description": "Your own tracking value, returned as {sub4} in postbacks and added to every start_url.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$"
            }
          },
          {
            "name": "sub5",
            "in": "query",
            "required": false,
            "description": "Your own tracking value, returned as {sub5} in postbacks and added to every start_url.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The offers for this user. The list can be empty.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OfferList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter is missing or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "invalid_country",
                  "message": "country is required: the two-letter ISO code of the user, for example US."
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "invalid_api_key",
                  "message": "This API key is not valid. Copy it again from the Integration tab of your app."
                }
              }
            }
          },
          "403": {
            "description": "The app is paused or its account is not approved (app_not_live), or we blocked this user (user_blocked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "app_not_live",
                  "message": "This app is not live, so it has no offers. It needs to be approved and active."
                }
              }
            }
          },
          "405": {
            "description": "Only GET is allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "method_not_allowed",
                  "message": "Use a GET request."
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The limit is shared with POST /v1/session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "rate_limited",
                  "message": "Too many requests. The limit is 600 per minute for each app."
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/session": {
      "post": {
        "summary": "Create an SDK session",
        "description": "Creates a single-use token for the mobile SDKs (Android, iOS, Flutter, React Native, Unity). It works once and for 10 minutes. Call it from your server only.",
        "operationId": "createSession",
        "security": [
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "user_id"
                ],
                "properties": {
                  "user_id": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._@:+\\-]{1,100}$",
                    "description": "The same user ID you receive in postbacks."
                  },
                  "sub1": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$",
                    "description": "Your own tracking value, returned in the postback."
                  },
                  "sub2": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$",
                    "description": "Your own tracking value, returned in the postback."
                  },
                  "sub3": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$",
                    "description": "Your own tracking value, returned in the postback."
                  },
                  "sub4": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$",
                    "description": "Your own tracking value, returned in the postback."
                  },
                  "sub5": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$",
                    "description": "Your own tracking value, returned in the postback."
                  }
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "user_id"
                ],
                "properties": {
                  "user_id": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._@:+\\-]{1,100}$",
                    "description": "The same user ID you receive in postbacks."
                  },
                  "sub1": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$",
                    "description": "Your own tracking value, returned in the postback."
                  },
                  "sub2": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$",
                    "description": "Your own tracking value, returned in the postback."
                  },
                  "sub3": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$",
                    "description": "Your own tracking value, returned in the postback."
                  },
                  "sub4": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$",
                    "description": "Your own tracking value, returned in the postback."
                  },
                  "sub5": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._~:@+\\-]{1,100}$",
                    "description": "Your own tracking value, returned in the postback."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The session was created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Session"
                }
              }
            }
          },
          "400": {
            "description": "user_id is missing or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "invalid_user_id",
                  "message": "user_id is required: 1 to 100 characters of letters, numbers, and . _ @ : + -"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "invalid_api_key",
                  "message": "This API key is not valid. Copy it again from the Integration tab of your app."
                }
              }
            }
          },
          "403": {
            "description": "The app is paused or its account is not approved (app_not_live), or the user is blocked (user_blocked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "user_blocked",
                  "message": "This user is blocked. Do not show the offerwall to this user."
                }
              }
            }
          },
          "405": {
            "description": "Use POST.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "method_not_allowed",
                  "message": "Use a POST request."
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The limit is shared with GET /v1/offers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "ok": false,
                  "error": "rate_limited",
                  "message": "Too many requests. The limit is 600 per minute for each app."
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stats": {
      "get": {
        "operationId": "getStats",
        "summary": "Statistics for a period",
        "description": "Clicks, conversions by state, and earnings, grouped by day (in the report time zone), country, offer, integration, or sub ID. Up to 92 days per request. Limit: 60 reporting requests per minute per app. Guide: https://docs.moonetix.com/reporting-api",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "First day, in the report time zone. Defaults to 29 days before to.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Last day, in the report time zone. Defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "timezone",
            "in": "query",
            "required": false,
            "description": "IANA time zone for the dates and times, for example America/New_York or UTC. Defaults to the time zone of the account.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group_by",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "day",
                "country",
                "offer",
                "integration",
                "sub1",
                "sub2",
                "sub3",
                "sub4",
                "sub5"
              ],
              "default": "day"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The statistics.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Stats"
                }
              }
            }
          },
          "400": {
            "description": "A parameter is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or wrong.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Reports are not available for this app (app_not_available): it was rejected, or its account is not active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Use GET.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Wait for Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/conversions": {
      "get": {
        "operationId": "listConversions",
        "summary": "List transactions",
        "description": "Every transaction of the period, oldest first, with cursor paging. Use it to reconcile postbacks. Guide: https://docs.moonetix.com/reporting-api#reconcile",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "First day, in the report time zone.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Last day, in the report time zone.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "timezone",
            "in": "query",
            "required": false,
            "description": "IANA time zone for the dates and times, for example America/New_York or UTC. Defaults to the time zone of the account.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "credited",
                "reversed"
              ]
            }
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._@:+\\-]{1,100}$"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          },
          {
            "name": "after",
            "in": "query",
            "required": false,
            "description": "next_cursor of the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of transactions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversionList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or wrong.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Reports are not available for this app (app_not_available): it was rejected, or its account is not active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Use GET.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Wait for Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "postback": {
      "get": {
        "summary": "Postback to your server",
        "description": "Moonetix calls your postback URL with GET for every event of every transaction. You choose the parameter names in your URL; the names below are the macros. Verify hash = HMAC-SHA256(transaction_id:user_id:reward:status, postback secret key). Answer with 2xx within 6 seconds; failures are retried up to 5 times. Guide: https://docs.moonetix.com/postbacks",
        "security": [],
        "parameters": [
          {
            "name": "user_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "{user_id}: the user ID from your offerwall link or API call."
          },
          {
            "name": "transaction_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "{transaction_id}: the same for every event of one transaction."
          },
          {
            "name": "event_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "{event_id}: unique for every event."
          },
          {
            "name": "status",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "enum": [
                1,
                2
              ]
            },
            "description": "{status}: 1 credited, 2 reversed."
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "credited",
                "reversed"
              ]
            },
            "description": "{state}: the status in words."
          },
          {
            "name": "reward",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "{reward}: the reward in your currency. Never negative."
          },
          {
            "name": "currency",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "{currency}: the name of your currency."
          },
          {
            "name": "payout",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "{payout}: what you earn, in US dollars. Never negative."
          },
          {
            "name": "offer_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "{offer_id}: the offer ID. 0 for test postbacks."
          },
          {
            "name": "offer_name",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "{offer_name}: the offer title."
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "{country}: two-letter country code of the user."
          },
          {
            "name": "device",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "desktop",
                "android",
                "ios"
              ]
            },
            "description": "{device}: the device of the user."
          },
          {
            "name": "ip",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "{ip}: the IP address the user started the offer from."
          },
          {
            "name": "hash",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{64}$"
            },
            "description": "{hash}: lowercase hex HMAC-SHA256 signature."
          },
          {
            "name": "sub1",
            "in": "query",
            "required": false,
            "description": "sub1 from the offerwall link, Offers API request, or SDK session, or empty.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sub2",
            "in": "query",
            "required": false,
            "description": "sub2 from the offerwall link, Offers API request, or SDK session, or empty.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sub3",
            "in": "query",
            "required": false,
            "description": "sub3 from the offerwall link, Offers API request, or SDK session, or empty.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sub4",
            "in": "query",
            "required": false,
            "description": "sub4 from the offerwall link, Offers API request, or SDK session, or empty.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sub5",
            "in": "query",
            "required": false,
            "description": "sub5 from the offerwall link, Offers API request, or SDK session, or empty.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "integration",
            "in": "query",
            "required": false,
            "description": "{integration}: how the user reached the offer: offerwall, api (Offers API), or sdk (mobile SDKs).",
            "schema": {
              "type": "string",
              "enum": [
                "offerwall",
                "api",
                "sdk"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Any 2xx tells Moonetix the event was handled."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your app's API key from Apps, your app, Integration. Send it as: Authorization: Bearer <key>. Server side only."
      }
    },
    "schemas": {
      "OfferList": {
        "type": "object",
        "required": [
          "ok",
          "currency",
          "bonus_percent",
          "history_url",
          "offers"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "currency": {
            "type": "string",
            "example": "Coins"
          },
          "bonus_percent": {
            "type": [
              "number",
              "null"
            ],
            "description": "Your running bonus, if any."
          },
          "history_url": {
            "type": "string",
            "format": "uri",
            "description": "The user's My offers page on the offerwall: every offer they started, with its status, rewards, and goals."
          },
          "offers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Offer"
            }
          }
        }
      },
      "Offer": {
        "type": "object",
        "required": [
          "id",
          "title",
          "category",
          "description",
          "goals",
          "reward",
          "reward_before_bonus",
          "payout_usd",
          "payout_type",
          "reward_max",
          "payout_max_usd",
          "thumbnail_url",
          "added_at",
          "start_url"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "The offer ID. Arrives as {offer_id} in postbacks.",
            "example": 58
          },
          "title": {
            "type": "string",
            "description": "The name users see. Arrives as {offer_name} in postbacks.",
            "example": "Nova Quest: reach level 10"
          },
          "category": {
            "type": "string",
            "enum": [
              "website",
              "app",
              "game",
              "service",
              "store",
              "social",
              "community",
              "signup",
              "sweeps",
              "other"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the user has to do to earn the reward, in the advertiser's words, for example: Download and install this app, then run it for 30 seconds. The steps are in goals. Every offer is also for new users only, with no VPN and no emulator. Plain text, not HTML, can contain line breaks."
          },
          "goals": {
            "type": "array",
            "description": "The steps in order, at least one. Each step is credited on its own and arrives as its own postback, with its own {transaction_id}. reward and payout_usd of the offer are the totals of all steps.",
            "items": {
              "type": "object",
              "required": [
                "name",
                "reward",
                "payout_usd"
              ],
              "properties": {
                "name": {
                  "type": "string",
                  "example": "Reach level 10"
                },
                "reward": {
                  "type": "number",
                  "example": 731
                },
                "payout_usd": {
                  "type": "number",
                  "example": 1.125
                }
              }
            }
          },
          "reward": {
            "type": "number",
            "description": "What the user gets, in your currency, after conversion rate, user split, bonus, and rounding. The same amount arrives as {reward} in the postback.",
            "example": 488
          },
          "reward_before_bonus": {
            "type": [
              "number",
              "null"
            ],
            "description": "The reward without your bonus. It differs from reward only while your app runs a bonus, so you can show \"was X\". null when no bonus is running."
          },
          "payout_usd": {
            "type": "number",
            "description": "What you earn when the offer is credited, in US dollars.",
            "example": 0.75
          },
          "payout_type": {
            "type": "string",
            "enum": [
              "fixed",
              "revshare"
            ],
            "description": "revshare offers have no fixed price: one start can be credited several times, each as its own postback. reward and payout_usd are then the lowest amount of one credit.",
            "example": "fixed"
          },
          "reward_max": {
            "type": [
              "number",
              "null"
            ],
            "description": "revshare offers: the most one credit can reach, in your currency. null for fixed offers.",
            "example": null
          },
          "payout_max_usd": {
            "type": [
              "number",
              "null"
            ],
            "description": "revshare offers: the most one credit can reach, as your earnings in US dollars. null for fixed offers.",
            "example": null
          },
          "thumbnail_url": {
            "type": "string",
            "format": "uri",
            "description": "The offer image. Offers without their own image get the default offer image, so it is never empty."
          },
          "added_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the offer went live, in Budapest time with the offset. Use it for \"New\" badges or to sort by newest."
          },
          "start_url": {
            "type": "string",
            "format": "uri",
            "description": "Starts the offer for this user. Open it unchanged in a new tab or in your app's browser."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "ok",
          "error",
          "message"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string",
            "description": "A stable error code."
          },
          "message": {
            "type": "string",
            "description": "A readable explanation for your logs."
          }
        }
      },
      "StatsRow": {
        "type": "object",
        "description": "One group. The group field is named after group_by (day, country, offer, integration, sub1..sub5); offer rows also have offer_name.",
        "additionalProperties": true,
        "required": [
          "clicks",
          "credited",
          "reversed",
          "payout_usd",
          "reward",
          "conversion_rate",
          "epc_usd"
        ],
        "properties": {
          "clicks": {
            "type": "integer"
          },
          "credited": {
            "type": "integer"
          },
          "reversed": {
            "type": "integer"
          },
          "payout_usd": {
            "type": "number"
          },
          "reward": {
            "type": "number"
          },
          "conversion_rate": {
            "type": [
              "number",
              "null"
            ],
            "description": "Clicks with at least one credited transaction, per 100 clicks. A multi-step offer counts once, so it never exceeds 100."
          },
          "epc_usd": {
            "type": [
              "number",
              "null"
            ]
          }
        }
      },
      "Stats": {
        "type": "object",
        "required": [
          "ok",
          "from",
          "to",
          "timezone",
          "group_by",
          "currency",
          "totals",
          "rows"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "timezone": {
            "type": "string",
            "description": "The time zone of the dates and times in this answer.",
            "example": "Europe/Budapest"
          },
          "group_by": {
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "totals": {
            "type": "object",
            "required": [
              "clicks",
              "credited",
              "reversed",
              "payout_usd",
              "reward"
            ],
            "properties": {
              "clicks": {
                "type": "integer"
              },
              "credited": {
                "type": "integer"
              },
              "reversed": {
                "type": "integer"
              },
              "payout_usd": {
                "type": "number"
              },
              "reward": {
                "type": "number"
              }
            }
          },
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StatsRow"
            }
          }
        }
      },
      "Conversion": {
        "type": "object",
        "required": [
          "transaction_id",
          "user_id",
          "status",
          "offer_id",
          "offer_name",
          "reward",
          "payout_usd",
          "country",
          "device",
          "sub1",
          "sub2",
          "sub3",
          "sub4",
          "sub5",
          "credited_at",
          "reversed_at"
        ],
        "properties": {
          "transaction_id": {
            "type": "string"
          },
          "user_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "credited",
              "reversed"
            ]
          },
          "offer_id": {
            "type": [
              "integer",
              "null"
            ]
          },
          "offer_name": {
            "type": "string",
            "description": "The offer title, the same as {offer_name} in postbacks."
          },
          "reward": {
            "type": [
              "number",
              "null"
            ]
          },
          "payout_usd": {
            "type": "number"
          },
          "country": {
            "type": [
              "string",
              "null"
            ]
          },
          "device": {
            "type": [
              "string",
              "null"
            ]
          },
          "sub1": {
            "type": [
              "string",
              "null"
            ]
          },
          "sub2": {
            "type": [
              "string",
              "null"
            ]
          },
          "sub3": {
            "type": [
              "string",
              "null"
            ]
          },
          "sub4": {
            "type": [
              "string",
              "null"
            ]
          },
          "sub5": {
            "type": [
              "string",
              "null"
            ]
          },
          "credited_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the transaction was credited. The date filter uses this day."
          },
          "reversed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "ConversionList": {
        "type": "object",
        "required": [
          "ok",
          "from",
          "to",
          "timezone",
          "currency",
          "next_cursor",
          "conversions"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "timezone": {
            "type": "string",
            "description": "The time zone of the dates and times in this answer.",
            "example": "Europe/Budapest"
          },
          "currency": {
            "type": "string"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Send as after to get the next page."
          },
          "conversions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Conversion"
            }
          }
        }
      },
      "Session": {
        "type": "object",
        "required": [
          "ok",
          "token",
          "expires_in",
          "expires_at"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "example": true
          },
          "token": {
            "type": "string",
            "pattern": "^sst_[A-Za-z0-9_-]{43}$",
            "description": "Pass it to Moonetix.open() in your app."
          },
          "expires_in": {
            "type": "integer",
            "example": 600,
            "description": "Seconds until the token expires."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    }
  }
}
