Skip to content
Quickstart
Documentation

Quickstart

One API key and one JSON envelope for 165 social, e-commerce and web data endpoints. Only successful calls that return data are charged.

Four steps to a first call

  1. Create an API key

    Create a key in the console and, if you like, limit the endpoints it can call (scopes). The full key is shown once, when you create it, so save it right away: the server keeps only a hash and cannot show it again.

    Shell
    export QOVIA_KEY="sk-qovia-…"

    Keys look like sk-qovia- plus 43 letters and digits.Create an API key

  2. Top up

    A new account gets 50 trial calls on any endpoint, counted only when a call returns data; after that, calls are paid from a prepaid balance. Top up in the console by card or Alipay (through Stripe), or with USDT (TRC-20): a card or Alipay payment is credited as soon as it succeeds, USDT about a minute after the transfer confirms. When the balance cannot pay for a call, nothing runs and you get 402 insufficient_balance.

    Top up
  3. Check the keyGET/v1/account

    Confirms the API key works and returns balance and plan. Not charged.

    cURL
    curl https://api.qovia.ai/v1/account \
      -H "Authorization: Bearer $QOVIA_KEY"
    Example response
    {
      "request_id": "00000000-0000-0000-0000-000000000000",
      "data": {
        "user": {
          "id": "00000000-0000-0000-0000-000000000000",
          "email": "you@example.com"
        },
        "api_key": {
          "id": "00000000-0000-0000-0000-000000000000",
          "name": "production",
          "scopes": [
            "*"
          ],
          "expires_at": null
        },
        "billing": {
          "balance_usd": "10.000000",
          "plan": "payg",
          "rpm_limit": null
        }
      },
      "meta": {
        "billed": false
      }
    }
  4. Make your first call

    Try Bilibili video search (GET /v1/raw/bilibili/search): it serves live data at $0.0005 per successful call.

    curl 'https://api.qovia.ai/v1/raw/bilibili/search?keyword=%E5%8F%B0%E7%A7%AF%E7%94%B5' \
      -H "Authorization: Bearer $QOVIA_KEY"

    Replace $QOVIA_KEY with your API key

    Example response200 OK
    {
      "request_id": "00000000-0000-0000-0000-000000000000",
      "data": {
        "items": [
          {
            "id": "soc_bil_2913ac9c522a",
            "src": "social",
            "platform": "bilibili",
            "lang": "zh-CN",
            "text": "「小白」全球芯片代工王!万字台积电发展史",
            "author": {
              "uid_hash": "ca5fa000e345",
              "mid": "8969156",
              "name": "小白测评"
            },
            "metrics": {
              "plays": 689248,
              "likes": 20365,
              "saves": 7230,
              "comments": 1348,
              "danmaku": 2676
            },
            "extra": {
              "source_id": "BV1DkoeYhExZ",
              "url": "https://www.bilibili.com/video/BV1DkoeYhExZ",
              "title": "「小白」全球芯片代工王!万字台积电发展史",
              "published_at": "2025-03-26T18:30:00+08:00",
              "category": {
                "id": 95,
                "name": "数码"
              },
              "tags": [
                "芯片",
                "数码",
                "台积电",
                "手机芯片"
              ],
              "cover": "https://i0.hdslb.com/bfs/archive/8f62d780e4e308bafa8c9f6c4d14ce5a28b2ce0b.jpg"
            },
            "prov": {
              "hash": "0xc16f694e973143c1",
              "ts": "2026-10-20T12:00:00+08:00",
              "source": "live"
            }
          }
        ],
        "cursor": 2,
        "has_more": true
      },
      "meta": {
        "billed": true,
        "charged_usd": "0.000500",
        "balance_usd": "9.999500",
        "empty": false
      }
    }

    Catalog sample, not live data

    Only a successful call that returns data is charged; its meta says what it cost and the balance left (charged_usd, balance_usd). Empty results and failures are not charged.

    See this endpoint's full reference

Base URL and authentication

Every endpoint lives under one base URL:

https://api.qovia.ai

Send the API key with every request, as a Bearer token in the Authorization header:

HTTP
Authorization: Bearer $QOVIA_KEY
  • You can send x-api-key: <API Key> instead; when both are present, Authorization wins.
  • The key is read from these two headers only, never from the URL or a cookie.
  • Call the API from your server: browser requests from other sites are refused (CORS), so the key never has to sit in web page code.
  • A missing, malformed, revoked or expired key gets 401 invalid_api_key; 30 failed attempts from one IP within a minute get 429 too_many_auth_failures.

Scopes

A key carries one or more scopes, picked when you create it; calling an endpoint outside them gets 403 scope_denied.

API key scopes
scopeGrants
*Every endpoint
searchCross-domain search
raw:*Every raw endpoint
raw:<platform>Every raw endpoint of one platform: raw:douyin, raw:kuaishou, raw:bilibili, raw:xingtu, raw:tieba, raw:zhihu, raw:wechat, raw:xiaohongshu, raw:pgy, raw:tiktok, raw:youtube, raw:instagram, raw:x, raw:reddit, raw:weibo, raw:toutiao, raw:taobao, raw:jd, raw:shopee, raw:amazon, raw:fliggy, raw:news, raw:cljx, raw:huahuo

Requests

GET endpoints
Parameters go in the query string and are converted to their declared types: integers as digits, booleans as true / false / 1 / 0 / yes / no, and arrays by repeating the name (?id=1&id=2).
POST endpoints
The body is one JSON object, sent with Content-Type: application/json. A body that is not valid JSON, or not an object, gets 400 invalid_params.
Validation
Only the listed parameters are accepted. An unknown one, a missing required one, or a wrong type or format gets 400 invalid_params, not charged. Its message starts with the parameter's name (item_id: …); a missing or unknown parameter starts it with params: ….
Defaults
Optional parameters you leave out get their defaults on the server (see each parameter's Default).

Responses

A success is HTTP 200 with the shared envelope. Here is a paid call in full:

Example response200 OK
{
  "request_id": "00000000-0000-0000-0000-000000000000",
  "data": {
    "items": [
      {
        "id": "soc_bil_2913ac9c522a",
        "src": "social",
        "platform": "bilibili",
        "lang": "zh-CN",
        "text": "「小白」全球芯片代工王!万字台积电发展史",
        "author": {
          "uid_hash": "ca5fa000e345",
          "mid": "8969156",
          "name": "小白测评"
        },
        "metrics": {
          "plays": 689248,
          "likes": 20365,
          "saves": 7230,
          "comments": 1348,
          "danmaku": 2676
        },
        "extra": {
          "source_id": "BV1DkoeYhExZ",
          "url": "https://www.bilibili.com/video/BV1DkoeYhExZ",
          "title": "「小白」全球芯片代工王!万字台积电发展史",
          "published_at": "2025-03-26T18:30:00+08:00",
          "category": {
            "id": 95,
            "name": "数码"
          },
          "tags": [
            "芯片",
            "数码",
            "台积电",
            "手机芯片"
          ],
          "cover": "https://i0.hdslb.com/bfs/archive/8f62d780e4e308bafa8c9f6c4d14ce5a28b2ce0b.jpg"
        },
        "prov": {
          "hash": "0xc16f694e973143c1",
          "ts": "2026-10-20T12:00:00+08:00",
          "source": "live"
        }
      }
    ],
    "cursor": 2,
    "has_more": true
  },
  "meta": {
    "billed": true,
    "charged_usd": "0.000500",
    "balance_usd": "9.999500",
    "empty": false
  }
}

Catalog sample, not live data

Success

Fields of a successful response
FieldTypeDescription
request_idstringThe call's ID (its usage record), also in the X-Request-Id header and in the console usage log.
dataobject | array | nullThe endpoint's data; see each endpoint's response example. An empty result may be an empty structure (e.g. empty items) or null; check meta.empty.
meta.billedbooleanWhether this call was charged to the balance; false for empty results.
meta.charged_usdstringAmount charged in USD, 6 decimals; "0.000000" when nothing was charged.
meta.balance_usdstringBalance after settlement, USD, 6 decimals.
meta.emptybooleanThe result is empty: not charged.
Empty results

An empty result is still HTTP 200 with meta.empty true, not charged; data may be an empty structure or null, so check meta.empty.

Errors

Fields of an error response
FieldTypeDescription
error.codestringThe error code; see the error table. Branch on code.
error.messagestringA short English explanation. One code can have several messages (the error table lists them all), so do not branch on it. Never contains the data source's own error text.
error.request_idstringSame as the X-Request-Id header (see below).
error.supportstringWhere to get help (Telegram); include the request_id so we can find the call.

Response headers

Response headers
HeaderSent withDescription
X-Request-IdEvery response except an unexpected plain-text 500Same as request_id in the body. For a reserved call (success, empty, or a failure after reservation) it is the usage record ID; a request refused before reservation keeps the X-Request-Id you sent, or gets a generated one.
X-Qovia-ChargedSuccess (including empty)Errors: upstream_busy, upstream_timeout, upstream_error, upstream_rejected, not_foundCharged for this call, USD, 6 decimals; 0.000000 when nothing was charged or it was refunded.
X-Qovia-BalanceSuccess (including empty)Errors: upstream_busy, upstream_timeout, upstream_error, upstream_rejected, not_foundBalance after settlement, USD, 6 decimals.
Retry-AfterErrors: too_many_auth_failures, rate_limited, too_many_unbilled, endpoint_busy, upstream_busySeconds to wait before retrying.
WWW-AuthenticateErrors: invalid_api_keyBearer realm="qovia".
AllowErrors: method_not_allowedThe methods this path supports.

/v1 only takes GET and POST: other methods (e.g. PUT, DELETE) get a framework 405 {"detail": "Method Not Allowed"}, and an unexpected server error may be a plain-text 500. Neither is charged.

Billing

  • Only successful calls that return data are charged.
  • Failures, empty results and timeouts are not charged: the reserved charge is given back automatically.
  • Calls are paid from a prepaid balance shared by every endpoint. Top up by card, Alipay or USDT (TRC-20); it is credited automatically.
  • When the balance cannot pay for a call, nothing runs and you get 402 insufficient_balance.
  • Every call reports its charge in meta and in the X-Qovia-Charged / X-Qovia-Balance headers.

Tiered prices

Each product is priced in marginal monthly tiers: within a calendar month, billed calls past a threshold are priced at the next tier.

Tiered prices per product
ProductBilled calls a monthPer 1kPer call
SearchAny volume$5$0.005
Raw endpoints0 – 5M$1.5$0.0015
Raw endpoints5M+$1$0.001

Fixed-price endpoints

These endpoints are not tiered: every successful call costs a fixed price.

Fixed-price endpoints
PriceEndpoints
$0.0005 / call$0.5 per 1kDouyin (8), Kuaishou (4), Bilibili (5), Douyin Xingtu (2)
$0.001 / call$1 per 1kDouyin (3), Kuaishou (5), Bilibili (3), Douyin Xingtu (3), Zhihu (8), TikTok (8), YouTube (6), Instagram (3), X (Twitter) (6), Reddit (6), Weibo (7), Toutiao (3)
$0.0012 / call$1.2 per 1kDouyin (1)
$0.0015 / call$1.5 per 1kCili Juxing (12), Huahuo (6)
$0.002 / call$2 per 1kInstagram (3)
$0.005 / call$5 per 1kKuaishou (2), WeChat Official Accounts & Channels (4), Xiaohongshu (RedNote) (6), Xiaohongshu Pugongying (1)
$0.01 / call$10 per 1kDouyin Xingtu (11), Xiaohongshu Pugongying (10)
$0.012 / call$12 per 1kDouyin (1)
$0.0135 / call$13.5 per 1kTaobao & Tmall (1)
$0.01691 / call$16.91 per 1kDouyin (1), WeChat Official Accounts & Channels (1), Xiaohongshu (RedNote) (2), Taobao & Tmall (1)
$0.0195 / call$19.5 per 1kJD.com (1)
$0.02536 / call$25.36 per 1kDouyin (1), Douyin Xingtu (1), Xiaohongshu (RedNote) (3), Xiaohongshu Pugongying (1)
$0.08451 / call$84.51 per 1kDouyin Xingtu (1)
$0.169 / call$169.02 per 1kWeChat Official Accounts & Channels (1)
$0.2535 / call$253.53 per 1kWeChat Official Accounts & Channels (1)
See pricing

Rate limits

Accounts and endpoints
No rate limits
  • No rate limits: Qovia does not limit requests per minute per account or per endpoint. Only repeated failed authentication from one IP is throttled (429 `too_many_auth_failures`).
  • When a 429 or 503 carries a Retry-After header, wait that many seconds before you retry. A 503 endpoint_unavailable has none: the endpoint is not live, so retrying will not help.

Errors

An error comes with its HTTP status and the error envelope:

Error response402
{
  "error": {
    "code": "insufficient_balance",
    "message": "insufficient balance for this request",
    "request_id": "00000000-0000-0000-0000-000000000000"
  }
}
Every error code
codeHTTPBillingDescription
invalid_api_key401Not chargedThe API key is missing, malformed, unknown, revoked or expired.
  • missing or invalid API key
  • API key has been revoked
  • API key has expired
  • invalid API key
too_many_auth_failuresRetryable429Not charged30 failed authentications from this IP within a minute; try again in 60 seconds.
  • too many failed authentications; try again later
account_disabled403Not chargedThe account is disabled.
  • account is disabled
payload_too_large413Not chargedThe request body is over 64 KiB; nothing ran.
  • request body too large; at most <bytes> bytes
endpoint_not_found404Not chargedNo such endpoint; check the method and path.
  • no endpoint <METHOD> <path>
  • no endpoint <METHOD> /v1/<path>
method_not_allowed405Not chargedThe path exists but takes another method; the Allow header names it.
  • use <METHODS>
endpoint_disabled410Not chargedThe endpoint has been retired.
  • <id> has been retired
scope_denied403Not chargedThis API key lacks the scope the endpoint requires.
  • this API key does not have scope <scope>
endpoint_unavailable503Not chargedThe endpoint is not available right now (no data source connected yet, or no price configured); nothing ran.
  • <id> is temporarily unavailable
  • pricing for this endpoint is not configured
invalid_params400Not chargedThe parameters failed validation: a required one is missing, a type or format is wrong, an array has more items than allowed, an unknown one was sent, or the POST body is not a JSON object. An error in one parameter starts with its name (item_id: …); a missing or unknown parameter starts with params: ….
  • <param>: <reason>
  • params: <reason>
  • <param>: array is too long (at most <n> items)
  • request body is not valid JSON
  • request body is nested too deeply
  • request body must be a JSON object
  • params are nested too deeply
rate_limitedRetryable429Not chargedOver the account's per-minute limit (sliding 60-second window); wait for Retry-After.
  • rate limit exceeded
too_many_unbilledRetryable429Not chargedIn the last 10 minutes at least 50 of your calls to data sources, and over 80% of them, came back empty, not found or rejected; slow down.
  • too many recent requests came back empty, not found or rejected; slow down. Not charged
endpoint_busyRetryable429Not chargedThe endpoint's per-second capacity across all users is full; retry in 1 second. This does not count toward your per-minute limit.
  • <id> is at capacity; retry shortly
insufficient_balance402Not chargedThe balance cannot pay for this call; top up first.
  • insufficient balance for this request
upstream_busyRetryable503RefundedThe data source is busy or cooling down; refunded. Retry after Retry-After.
  • the data source is busy; retry later; not charged
upstream_timeout504RefundedThe data source timed out; refunded.
  • the data source timed out; not charged
upstream_error502 / 503RefundedThe data source failed; refunded.
  • the data source failed; not charged
upstream_rejected400RefundedThe data source rejected these parameters (well-formed, but not accepted); refunded.
  • the data source rejected these parameters; not charged
not_found404RefundedThe data source has no such item (deleted, or the ID does not exist); refunded.
  • the data source has no such item; not charged
reservation_expired504RefundedThe call took too long and was refunded automatically; no data is returned.
  • the request took too long and was not charged

Branch on error.code; message is for people and can be worded several ways.

For AI agents and tools

AI tools can call these endpoints directly over MCP, and the same catalog is published in machine-readable form for code generators: