Jobs & Hiring

How do you get buyer project requests from Kwork via API?

Call ReefAPI's kwork search action and read open buyer requests back as JSON with id, title, full description, budget, offers_received, category, deadline and coarse buyer history. There is no second lookup: Kwork publishes no per-project page, so everything is already on the row. The setting that decides your cost is max_pages, because budget and offer-count filters are not available at the source and are applied on ours.

Kwork project exchange engineLive JSON4 steps1,000 free credits

This guide demonstrates the real Kwork project exchange API engine with a captured response from . The example is only published because the engine passed the SEO snapshot gate.

Use case

Freelance lead generation, bid-board monitoring, marketplace demand research and order aggregation.

Step by step

Call the live endpoint

  1. 1

    List the categories and see where the demand is

    POST /kwork/v1/categories with an empty body. You get the whole exchange tree with a live count of open requests in each category, plus the slug to use in the next call.

  2. 2

    Search with a page budget you have chosen

    POST /kwork/v1/search with category, any of budget_min, budget_max or max_offers, and max_pages set to the cost you accept. Omit the category to browse the whole board.

  3. 3

    Read budget_exhausted before you read the rows

    If budget_exhausted is true, the page budget stopped the call rather than the board running out. Raise max_pages or page with offset; if it is false, you have seen everything that matched.

  4. 4

    Rank by competition, not by recency

    Sort your rows on offers_received and the buyer's hire rate. A fresh brief with nine offers is worse than a day-old one with none, and both facts are on the row already.

Code

Copy the request

These snippets use the captured request params for kwork/v1/search.

curl -X POST https://api.reefapi.com/kwork/v1/search \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"limit":10}'
MCP one-liner
Ask your MCP-connected assistant: call reefapi.kwork.search with {"limit":10}.
Real response

Captured output from ReefAPI

Captured on UTC. The response below is the committed snapshot, including the API envelope and metadata.

Captured request
{
  "method": "POST",
  "url": "https://api.reefapi.com/kwork/v1/search",
  "headers": {
    "x-api-key": "$REEF_KEY",
    "content-type": "application/json"
  },
  "body": {
    "limit": 10
  }
}
Captured response
{
  "ok": true,
  "meta": {
    "api": "kwork",
    "endpoint": "search",
    "mode": "live",
    "latency_ms": 1400.1,
    "record_count": 10,
    "bytes": 305959,
    "cache_hit": false,
    "pii_redacted": true,
    "pages_read": 1,
    "page_budget": 3,
    "stop_reason": "limit_reached",
    "charged_credits": 1,
    "version": "1.0.0",
    "request_id": "c13bca1dc0c644e0",
    "queue_ms": 1.1
  },
  "data": {
    "projects": [
      {
        "id": 3260349,
        "title": "Монтаж роликов на английском языке до 30 минут",
        "description": "Прочтите задание внимательно! \nИщу добросовестного исполнителя для постоянного и длительного сотрудничества.\nЗадание: Нужно монтировать ролики на английском языке (знание языка приветствуется), длительность каждого ролика — 25–30 минут, тема — детективные истории.\nПроект скромный, но стабильный и долгосрочный, монтаж будет требоваться постоянно!\nОтличный вариант для студентов или тех, кто хочет стабильную подработку.\nРолики состоят из озвучки, музыки, фотографий и стоковых видео.\nВАЖНО! Стоковые видео необходимо Вам подбирать по смыслу и скачивать только с сайта Canva (подпис",
        "budget": 1000,
        "budget_ceiling": 1000,
        "currency": "RUB",
        "offers_received": 0,
        "views": 0,
        "category_id": 78,
        "category": "Video filming and editing",
        "category_slug": "editing-media",
        "delivery_days_max": 10,
        "status": "active",
        "status_label": "Сбор предложений",
        "is_active": true,
        "is_archived": false,
        "time_left": "23 ч. 59 мин.",
        "created_at": "2026-09-28T14:58:48",
        "expires_at": "2026-09-29T14:58:48",
        "attachments": 0,
        "language": "ru",
        "buyer": {
          "id": 14335208,
          "projects_posted": 56,
          "hire_rate_percent": 80,
          "badges": [
            "[trimmed-depth]",
            "[trimmed-depth]"
          ]
        }
      },
      {
        "id": 3260346,
        "title": "Заполнить 300 карточек товаров по шаблону",
        "description": "Здравствуйте! Нужен исполнитель для заполнения карточек товаров на сайте по готовому шаблону. Работа простая и механическая, но требует времени и внимательности. Опыт не нужен — все данные я предоставлю, вам нужно только скопировать информацию из таблицы и вставить её в нужные поля на сайте.\nЧто за задача:\nЕсть сайт, на котором нужно заполнить 300 карточек товаров. Для каждой карточки есть готовый шаблон с полями. Все данные — названия, характеристики, описания, цены, размеры — я предоставлю в таблице Excel. Вы открываете строку, копируете значение и вставляете в соответствую",
        "budget": 4000,
        "budget_ceiling": 12000,
        "currency": "RUB",
        "offers_received": 0,
        "views": 1,
        "category_id": 73,
        "category": "Website copy and content",
        "category_slug": "creative-writing",
        "delivery_days_max": 10,
        "status": "active",
        "status_label": "Сбор предложений",
        "is_active": true,
        "is_archived": false,
        "time_left": "23 ч. 59 мин.",
        "created_at": "2026-09-28T14:56:47",
        "expires_at": "2026-09-29T14:58:43",
        "attachments": 0,
        "language": "ru",
        "buyer": {
          "id": 25340217,
          "projects_posted": 1,
          "hire_rate_percent": 0
        }
      },
      {
        "id": 3260342,
        "title": "Написание текста",
        "description": "1. Писать продающие заголовки под требования маркетплейсов;\n2. Превращать сухие характеристики в понятные выгоды для покупателя;\n3. Структурировать тексты так, чтобы их было удобно читать (списки, абзацы, акценты);\n4. Объяснять технические термины простым языком;\n5. Готовить тезисы для инфографики.",
        "budget": 3000,
        "budget_ceiling": 9000,
        "currency": "RUB",
        "offers_received": 4,
        "views": 62,
        "category_id": 73,
        "category": "Website copy and content",
        "category_slug": "creative-writing",
        "delivery_days_max": 10,
        "status": "active",
        "status_label": "Сбор предложений",
        "is_active": true,
        "is_archived": false,
        "time_left": "23 ч. 55 мин.",
        "created_at": "2026-09-28T14:51:24",
        "expires_at": "2026-09-29T14:54:15",
        "attachments": 0,
        "language": "ru",
        "buyer": {
          "id": 25340156,
          "projects_posted": 1,
          "hire_rate_percent": 0
        }
      }
    ],
    "total_count": 659,
    "returned": 10,
    "offset": 0,
    "pages_read": 1,
    "page_budget": 3,
    "budget_exhausted": false,
    "scanned": 12,
    "filters_applied": {},
    "currency": "RUB",
    "source": "kwork.ru"
  }
}
Manual way

Why this is hard manually

Kwork has two sides and they are easy to confuse. The seller catalogue is the part everybody sees: fixed-price services that freelancers list. The project exchange is the other side, where buyers describe what they need and collect offers. Only the second one tells you what work is being asked for right now, and it is a different surface with different data.

The distinction is checkable rather than a matter of labels, which is worth knowing because an aggregator that gets it wrong ships the wrong product. Every row on the exchange carries the number of offers it has already received, the buyer's budget cap, a status of 'collecting offers' and badges describing the buyer's purchase history. A seller listing has none of those fields, because none of them would mean anything on one.

The exchange is also a Russia-only product. It lives on the .ru domain and not the .com one - we checked the .com sitemaps as well as the site itself before concluding that. Every request is written in Russian and every budget is in roubles. If you are building for an English-speaking audience, that is the thing to decide before you write any code.

Scraping it yourself runs into the usual pair of problems. The records are not in the HTML you would parse with a selector, they are in a data island the page hands to its own front end, so a naive parser finds an empty board. And the filters you would reach for are not there: the budget and competition filters exist in the interface but do not apply over HTTP.

ReefAPI way

Why ReefAPI solves it

One call is the entire record. Kwork publishes no per-project page, so unlike most bid boards there is no detail endpoint to pay for - the full brief, the budget, the deadline, the category, the offer count and the buyer block all arrive on the search row. On the sample we measured, every content field was populated on every row. Your cost is exactly the pages you read and nothing else.

max_pages is the cost control, and you should set it deliberately. Because budget and offer-count filters cannot be pushed to the source, a narrow filter would otherwise walk the whole board looking for matches. max_pages caps how many exchange pages a single call may read, whatever the filter, with a hard ceiling above which it cannot be raised. Set it to the cost you are willing to pay, not to the result size you hope for.

Then read the response rather than guessing what it cost. Every search returns pages_read, page_budget and budget_exhausted. That last flag is the one that matters: it distinguishes a result cut short by your budget from one that genuinely ran out of matches. Without it, 'two results' is ambiguous and you would not know whether raising the budget would find more.

offers_received is the field that makes the engine worth calling. On a bid board the wasted effort goes into briefs that already have a queue behind them, and Kwork publishes the count on the request itself. max_offers filters on it directly, so 'open requests in this category with at most three offers so far' is one call. Of the open projects in our measurement, a substantial share had received no offers at all, so the winnable set is real and not a rounding error.

Validate the category or we will do it for you, loudly. This is the trap on this source: ask Kwork for a category id that does not exist and it does not return an error, it quietly returns the entire board with the same total as no filter at all. A pass-through integration would answer a narrow question with everything and report success. The engine checks the value against the live category tree and refuses an unknown one with INVALID_PARAM, and the refusal costs no upstream call.

The categories action doubles as a demand signal. It returns the whole exchange tree with the number of open requests in each category right now, which tells you where buyers are actually spending before you search anything. The stats action returns Kwork's own thirty-day totals - projects posted, orders completed and their rouble value - as the marketplace publishes them.

The keyword is matched across the body as well as the title, by Kwork itself rather than by us. That means a term describing the work still finds a brief that never names it. Because the board is Russian, Russian terms match far more than English ones, and that is a property of the source rather than of the engine.

Nothing identifies the buyer. Their display name, avatar and profile link are dropped before the response leaves us. What remains is an opaque id and business signal: how many projects they have posted, the share of those they actually hired for, and the purchase-level badges the marketplace awards. That hire rate is the closest thing the board has to a 'will this person ever pay anyone' score.

FAQ

Questions developers ask

Do I need a Kwork account?

No. The exchange is public and nothing is tied to an account of yours. You send a ReefAPI key, and there is no Kwork login, token or OAuth flow involved.

Is there a detail endpoint for a single project?

No, and that is the source's doing rather than a gap on our side. Kwork publishes no per-project page at all, so the search row is the complete record. It also means you never pay for a second call to fill in the description or the budget.

Why is budget filtering applied on your side?

Because it does not work at the source. Budget, offer-count and hiring filters exist in Kwork's interface but do not take effect over HTTP in any parameter shape we could find, tried as a query string and as a form post. We apply them to the pages your call reads, which is why max_pages exists.

What happens if I pass a category that does not exist?

You get INVALID_PARAM and no upstream call is spent. We check against the live category tree, because Kwork itself would return the entire board with the same total as no filter - a wrong answer reported as a successful one.

Is the content in English?

No. The exchange is a Russia-only product and every request is in Russian, with budgets in roubles. The buyer-project surface does not exist on kwork.com. If you need English-language briefs this is the wrong source.

How deep does the board go?

The open board is a few dozen pages of twelve, which is the whole exchange rather than a limit we impose. offset pages through it, and total_count tells you how many requests matched your keyword and category at the source.

What is the difference between budget and budget_ceiling?

budget is the cap the buyer set on the request. budget_ceiling is the higher figure they could still go to where the marketplace publishes one. Ranking on the first is honest; treating the second as the price is not.

Can I tell whether a project is still open?

Yes. Every row carries a status, the marketplace's own status label, an expiry timestamp and the time left, alongside the offer count. Those four together are a better availability signal than a single open-or-closed flag.