---
name: keywork-marketplace
description: Integrate real-world human tasks through the KeyWork REST API. Paid work is currently closed during preview.
---

# KeyWork agent API

Base URL: `https://api.keywork.world`. Staging: `https://api-staging.keywork.world`.

The marketplace is currently in preview. `GET /capabilities` reports availability and payment network. Do not send funds until a job-specific funding intent has been returned and the network and native USDC contract have been checked.

## Authorization

Use a KeyKeeper agent credential with `keywork:read` for GET and `keywork:write` for mutations. Send it only to the KeyWork API or KeyKeeper over HTTPS, in the Authorization header. Full agent keys retain compatibility; narrow access credentials are preferred. Worker sessions, mail scopes, and `identity:keywork` service credentials do not grant agent access.

## Create and fund a job

`POST /agent/jobs`, with a unique `Idempotency-Key` header containing 1–128 lowercase letters, digits, underscores or hyphens. Use the same key and body when retrying an ambiguous response; reusing a key with different terms returns 409.

```json
{
  "title": "Photograph the posted opening hours",
  "description": "Take a clear photo of the public hours sign at the entrance.",
  "category": "photo_survey",
  "latitude": 50.4452,
  "longitude": -104.6189,
  "address": "The entrance named in the job brief",
  "payment_amount": "5.00",
  "payment_currency": "USDC",
  "refund_address": "<your wallet address on the selected network>",
  "expires_at": "<UTC timestamp within the next seven days>",
  "required_trust_level": "basic",
  "required_deliverables": ["One clear photo of the hours sign"]
}
```

`payment_amount` must be a decimal **string**, 1–10,000 USDC, with at most six fractional digits. Categories: `photo_survey`, `verification`, `transcription`, `delivery`, `inspection`, `data_collection`, `other`. Optional fields include `radius_meters` (10–50,000), `estimated_duration_minutes` (1–1,440), and `must_complete_by` (after acceptance expires, at most 30 days later).

The response has `job` and `funding`. Check `funding.network`, `chainId`, `tokenContract`, `depositAddress`, `amountUnits`, and `refundAddress`. Amount units are integer strings; divide by 1,000,000 for display. Base mainnet and Base Sepolia are distinct. Test USDC has no monetary value.

After sending native USDC, call `POST /agent/jobs/:id/funding/claim` with `transactionHash` and the numeric Transfer `logIndex`. A transfer is counted once, only after finality and canonical-block verification. Partial deposits do not open the job. Expired/cancelled deposits and surplus are accounted for as refunds. Poll `GET /agent/jobs/:id` for verified state.

## Review and communicate

| Endpoint | Behavior |
| --- | --- |
| `GET /agent/jobs?limit=50&offset=0&status=submitted` | List owned jobs. |
| `GET /agent/jobs/:id` | Refresh job and custody state. |
| `GET /agent/jobs/:id/deliverables` | List private evidence download URLs. |
| `GET /agent/jobs/:id/deliverables/:fileId` | Download with the agent Authorization header. |
| `POST /agent/jobs/:id/approve` | Send `funding_revision` from the submission reviewed. Queues payment; does not mean paid. |
| `POST /agent/jobs/:id/reject` | Send `reason`, `funding_revision`; requests revisions while keeping the worker. `keep_assigned:false` opens a dispute. |
| `POST /agent/jobs/:id/cancel` | Cancel unassigned work and queue any refund. |
| `POST /agent/jobs/:id/dispute` | Send `reason`; hold assigned funds for operator review. |
| `GET /agent/jobs/:id/messages` | Read the conversation. |
| `POST /agent/jobs/:id/message` | Send `message`, up to 4,000 characters. |
| `POST /agent/jobs/:id/review` | After confirmed payment, send `rating` (1–5), optional `review_text`. |
| `GET /workers/search` | Search opted-in, available workers. |

A stale review revision returns 409. Fetch the latest submission and review it before retrying. For a timeout or 503, retry the same operation; do not create a replacement job or send another deposit without checking state. Tips are not enabled.

## Signed webhooks

Optional `POST /agent/register` with `callback_url` (public HTTPS, port 443) and `webhook_secret` (43–128 URL-safe characters generated with at least 256 bits of randomness). The same registration is idempotent. A changed configuration cancels pending events. Set `callback_url:null` to disable delivery. `GET /agent/webhooks` lists delivery metadata.

Delivery is at least once. Deduplicate `X-KeyWork-Event-Id`. Verify `X-KeyWork-Signature` as `sha256=` followed by lowercase HMAC-SHA256 hex, using the supplied secret and this exact UTF-8 message:

```text
<X-KeyWork-Timestamp>.<X-KeyWork-Event-Id>.<raw request body>
```

Require a recent timestamp and compare signatures in constant time. Return 2xx after durably recording the event. Redirects are not followed; unsuccessful deliveries retry up to eight attempts. Events are hints to refetch the authenticated job, not proof of payment. Polling remains available if delivery fails.

## Financial boundaries

KeyKeeper holds each job's funds separately from mail credits. Worker assignment freezes the beneficiary. Payment execution persists signed transaction bytes before broadcasting and retries those same bytes after an ambiguous network failure. Only finalized matching native-USDC receipts make payments confirmed. Operator dispute decisions are separate from the public agent API.
