{
  "openapi": "3.1.0",
  "info": {
    "title": "Sharklio Offers API",
    "version": "1.0.0",
    "description": "List the tasks and clicks available to one of your users, and receive results through postbacks. Full guide: https://docs.sharklio.com/offers-api",
    "contact": {
      "name": "Sharklio partners",
      "email": "partners@sharklio.com",
      "url": "https://docs.sharklio.com"
    },
    "termsOfService": "https://sharklio.com/terms"
  },
  "servers": [
    {
      "url": "https://api.sharklio.com"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "paths": {
    "/v1/offers": {
      "get": {
        "operationId": "listOffers",
        "summary": "List offers for a user",
        "description": "Returns the tasks and clicks 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. Replaces device and also matches browser-targeted offers.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Only offers of this type.",
            "schema": {
              "type": "string",
              "enum": [
                "task",
                "click",
                "offer"
              ]
            }
          }
        ],
        "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 not live.",
            "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.",
            "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"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "postback": {
      "get": {
        "summary": "Postback to your server",
        "description": "Sharklio 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.sharklio.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,
                3,
                4
              ]
            },
            "description": "{status}: 1 credited, 2 reversed, 3 pending, 4 rejected."
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "credited",
                "reversed",
                "pending",
                "rejected"
              ]
            },
            "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}"
          },
          {
            "name": "offer_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "click",
                "task",
                "offer"
              ]
            },
            "description": "{offer_type}"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "{country}"
          },
          {
            "name": "device",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "desktop",
                "android",
                "ios"
              ]
            },
            "description": "{device}"
          },
          {
            "name": "ip",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "{ip}: the IP address the user completed the offer from."
          },
          {
            "name": "hash",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{64}$"
            },
            "description": "{hash}: lowercase hex HMAC-SHA256 signature."
          }
        ],
        "responses": {
          "200": {
            "description": "Any 2xx tells Sharklio 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",
          "count",
          "history_url",
          "disputes_url",
          "offers"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "currency": {
            "type": "string",
            "example": "Coins"
          },
          "bonus_percent": {
            "type": [
              "number",
              "null"
            ],
            "description": "Your running bonus, if any."
          },
          "count": {
            "type": "integer"
          },
          "history_url": {
            "type": "string",
            "format": "uri",
            "description": "The user's History page on the offerwall."
          },
          "disputes_url": {
            "type": "string",
            "format": "uri",
            "description": "The user's My disputes page on the offerwall."
          },
          "offers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Offer"
            }
          }
        }
      },
      "Offer": {
        "type": "object",
        "required": [
          "id",
          "type",
          "title",
          "category",
          "description",
          "instructions",
          "proof",
          "reward",
          "reward_before_bonus",
          "payout_usd",
          "devices",
          "thumbnail_url",
          "view_seconds",
          "time_limit_hours",
          "review_window_minutes",
          "frequency",
          "approval_rate",
          "avg_completion_seconds",
          "added_at",
          "start_url"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "The offer ID. Arrives as {offer_id} in postbacks.",
            "example": 58
          },
          "type": {
            "type": "string",
            "enum": [
              "task",
              "click",
              "offer"
            ],
            "description": "task: steps and proof, reviewed by the advertiser. click: a page view with a timer, credited right away. offer: one or more steps in the advertiser's app or site, each credited when the advertiser's server confirms it."
          },
          "title": {
            "type": "string",
            "description": "The name users see. Arrives as {offer_name} in postbacks.",
            "example": "Create a free Nova Notes account"
          },
          "category": {
            "type": "string",
            "enum": [
              "website",
              "app",
              "game",
              "service",
              "store",
              "social",
              "community",
              "signup",
              "other"
            ]
          },
          "description": {
            "type": "string",
            "maxLength": 140,
            "description": "A one-line summary for offer cards."
          },
          "instructions": {
            "type": "string",
            "description": "The full steps as plain text, one step per line. Not HTML."
          },
          "proof": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "required": [
                  "type",
                  "requirement"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "screenshot",
                      "text",
                      "both"
                    ]
                  },
                  "requirement": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "What the proof must show."
                  }
                }
              }
            ],
            "description": "Proof needed for tasks. null for clicks and offers."
          },
          "goals": {
            "type": [
              "array",
              "null"
            ],
            "description": "Offers: the steps in order. Each step is credited on its own and arrives as its own postback, with {offer_name} set to the offer title and the step name. reward and payout_usd of the offer are the totals of all steps. null for tasks and clicks.",
            "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 running bonus. 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
          },
          "devices": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "desktop",
                "android",
                "ios"
              ]
            }
          },
          "thumbnail_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "The offer image."
          },
          "view_seconds": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Clicks: how long the page has to stay open."
          },
          "time_limit_hours": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Tasks: how long the user has to send the proof after starting. Offers: how long the steps can be completed after starting."
          },
          "review_window_minutes": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Tasks: the longest review time, 30 minutes to 3 days. Not reviewed by then means approved automatically."
          },
          "frequency": {
            "type": "string",
            "description": "How often one user can do the offer: once, unlimited, or an interval such as 24hours or 7days.",
            "example": "once"
          },
          "approval_rate": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Approved share of reviewed tasks, in percent. null until at least 10 were reviewed."
          },
          "avg_completion_seconds": {
            "type": [
              "integer",
              "null"
            ],
            "description": "How long approved users usually needed. null until there is enough data."
          },
          "added_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the offer went live, in UTC."
          },
          "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."
          }
        }
      }
    }
  }
}
