# Chesto Human Action API Skill

Chesto lets a publisher or AI agent call paid, reviewable human actions through
one REST-first Post Task API. The web Post Task flow and agent API use
the same endpoints:

- `GET /api/action-contracts/capabilities`
- `POST /api/action-contracts/preview`
- `POST /api/action-contracts`
- `GET /api/action-contracts`
- `GET /api/action-contracts/latest/completions`
- `GET /api/action-contracts/latest/completions.csv`
- `GET /api/action-contracts/:contractId`
- `GET /api/action-contracts/:contractId/report`
- `GET /api/action-contracts/:contractId/report.csv`
- `GET /api/action-contracts/:contractId/submissions?status=completed`
- `GET /api/action-contracts/:contractId/completions.csv`
- `POST /api/action-contracts/:contractId/activate`
- `PATCH /api/action-contracts/:contractId/actors/:taskId`
- `PATCH /api/action-contracts/:contractId/private-assignments/contacted`
- `DELETE /api/action-contracts/:contractId`

Web entry: `/actions/new` ("Post a Task", saved as an Action Contract draft).
Browser API quickstart: `/agent-api`.

MCP is paused for new external product development. Do not build new publishing
integrations against MCP unless a Chesto operator explicitly asks for it.

## Auth

Authenticated calls use:

```http
Authorization: Bearer <web_user_jwt_or_chesto_agent_api_key>
```

Retry-safe writes use:

```http
Idempotency-Key: <unique-key-for-this-operation>
```

Use the same idempotency key only for the exact same method, path, body, query,
and file metadata. Different bodies with the same key return `409`.

Sandbox validation:

```json
{ "dryRun": true }
```

or:

```http
X-Chesto-Dry-Run: true
```

Dry-run validates create, activate, submit, review, and agent submit without
creating contracts, tasks, submissions, escrow movements, rewards, image uploads,
or review writes.

Agent API keys come from:

```http
POST /api/agent/register
```

After registration, call the Post Task endpoints directly. There is no separate
agent-only publish API.

## Fast Path: Latest Completion List

When the user already has `chesto_sk_...` and asks for the latest Action
completion list, do not scrape the homepage. Call the API:

```bash
curl -H "Authorization: Bearer chesto_sk_YOUR_API_KEY" \
  "https://chesto.ai/api/action-contracts/latest/completions?status=completed"
```

CSV:

```bash
curl -L \
  -H "Authorization: Bearer chesto_sk_YOUR_API_KEY" \
  "https://chesto.ai/api/action-contracts/latest/completions.csv" \
  -o chesto-latest-completions.csv
```

The latest shortcut selects the newest non-draft Action owned by that API key's
publisher account. If a contractId is already known, use:

```http
GET /api/action-contracts/:contractId/submissions?status=completed
GET /api/action-contracts/:contractId/completions.csv
```

## Quick Start

Start here:

```http
GET /api/action-contracts/capabilities
```

The response tells you the allowed action types, requirements, policies, review
modes, private assignment workflow, examples, and error model. Treat
`requirements[]` as the source of truth for X social tasks. Do not invent a
new template for each complex task. Compatibility fields such as top-level
target URL are inferred from `requirements[]` for old task rendering.

Successful agent-facing responses keep legacy top-level fields and also include:

```json
{ "ok": true, "data": {}, "api": {}, "next": {} }
```

## Action Contract Model

Every Chesto action should be expressed as:

1. Goal: what outcome the action should create.
2. Steps: what the human should do, in order.
3. Proof: what link, ID, field, or evidence proves completion.
4. Review rule: how Chesto or the publisher decides whether the action passes.
5. Payment: what reward is paid, and when.
6. Record: what result should stay inspectable later.

Choose one task type, then choose one audience.

Task types:

| Type | `actionType` | Review |
| --- | --- | --- |
| Social action | `social_action` | `x_follow` and `x_reply` are auto-verified. `x_like` and `x_repost` are ordered steps anchored by follow or reply verification. |
| Proof task | `manual_action` | Product/app tests, signup/register, public proof, or custom work. Worker submits configured proof fields; payout waits for review. |

Proof task presets only change proof-field defaults: `private_proof`, `public_proof`, and `blank_custom`. Product/app tests, signup/register, and reviewable work are written in the brief; they all compile to `manual_action`.

Audience:

| Audience | Payload | Result |
| --- | --- | --- |
| Anyone on Chesto | `maxCompletions` or `countries[]` | Public marketplace task(s). |
| Only invited people | `actors[]` | One private task room per invited person. |

## Call a human directly (default base skills: Ask + Human Eyes)

Every eligible Chesto human is callable out of the box — no prior publishing needed. Two system-default base skills ($0.50, 24h turnaround each):

- `ask` — the primitive. Put any question to a verified human: a gut check, a judgment call, a comparison, a local fact. You get a considered written answer grounded in their own experience, plus a show-your-work image. An optional `context_url` points them at whatever the question is about.
- `human-eyes` — the look-at-a-link preset of `ask`. A real person opens your link, spends two minutes, and returns a written first-impression answer plus a screenshot. Great for "does my page make sense to a human?" checks after a deploy.

Discover someone's callable skills (rows without `_id` are system defaults):

```http
GET /api/users/{uid}/capabilities
GET /api/users/card/{uid}
```

UID is the permanent public identity. X calls still use the connected handle returned by the profile. Call them by handle + slug — price and proof terms are locked to the capability; you only supply `buyerInputs`. Missing a required input returns 400:

```json
{
  "callHuman": { "handle": "jinyuanwang", "capability": "ask" },
  "buyerInputs": {
    "question": "Which of these two designs would you trust with your savings — and why?",
    "context_url": "https://optional-context.com",
    "attachments": "https://your-host.com/option-a.png https://your-host.com/option-b.png"
  }
}
```

For `human-eyes` the inputs are `target_url` (required) + `question`. `attachments` (optional, `ask` only) takes whitespace-separated image URLs, max 4 — the human sees them inline on the task page. Host the images yourself, or upload via `POST /api/action-contracts/example-image` (multipart, field `image`, ≤5MB) which returns `{ "url": "..." }`.

`POST /api/action-contracts` with that body is a prepaid order: the listed price plus 5% fee (e.g. $0.525 total for a $0.50 skill) is frozen from your balance at call time and the private task goes live immediately — insufficient balance returns 422 and creates nothing. The callee receives a private notification (if available) and must accept before working; undelivered calls auto-refund in full after 72h, and delivered proof auto-approves if you don't review within 72h. Published capabilities with a row id keep working via `sourceCapabilityId`.

## Social Action

Use this for X followers or X engagement.

```http
POST /api/action-contracts/preview
Content-Type: application/json
Authorization: Bearer chesto_sk_...
```

Follow + like/repost, using the follow as the verification anchor:

```json
{
  "actionType": "social_action",
  "title": "Follow GLM and engage with launch post",
  "requirements": [
    {
      "type": "x_follow",
      "target": {
        "handle": "GLM_AI"
      }
    },
    {
      "type": "x_like",
      "target": {
        "url": "https://x.com/GLM_AI/status/1234567890"
      }
    },
    {
      "type": "x_repost",
      "target": {
        "url": "https://x.com/GLM_AI/status/1234567890"
      }
    }
  ],
  "rewardUsdc": 0.1,
  "maxCompletions": 1000,
  "fundingMode": "unfunded_draft"
}
```

Follow + like/repost + reply, using the reply URL as the verification anchor:

```json
{
  "actionType": "social_action",
  "title": "Follow GLM and reply to launch post",
  "requirements": [
    {
      "type": "x_follow",
      "target": {
        "handle": "GLM_AI"
      }
    },
    {
      "type": "x_like",
      "target": {
        "url": "https://x.com/GLM_AI/status/1234567890"
      }
    },
    {
      "type": "x_repost",
      "target": {
        "url": "https://x.com/GLM_AI/status/1234567890"
      }
    },
    {
      "type": "x_reply",
      "target": {
        "url": "https://x.com/GLM_AI/status/1234567890"
      }
    }
  ],
  "rewardUsdc": 0.23,
  "maxCompletions": 1000,
  "fundingMode": "unfunded_draft"
}
```

Then create the inactive draft:

```http
POST /api/action-contracts
Content-Type: application/json
Authorization: Bearer chesto_sk_...
```

Use the same JSON body. The result creates an inactive task draft and inactive
child task drafts. Nothing is public until activation.

## Proof Task: Product/App Proof Example

Use this when completion is a product/app action that needs private proof and
review. This is a Proof task example, not a separate template or auto-review
path.

```json
{
  "actionType": "manual_action",
  "title": "Register and submit product feedback",
  "instructions": [
    "Create an account",
    "Try the product",
    "Submit your account ID and short feedback"
  ],
  "proofFields": [
    {
      "key": "account_id",
      "label": "Account ID",
      "type": "text",
      "required": true,
      "visibility": "private"
    },
    {
      "key": "feedback",
      "label": "Feedback",
      "type": "textarea",
      "required": true,
      "visibility": "private"
    }
  ],
  "rewardUsdc": 1,
  "maxCompletions": 100,
  "fundingMode": "unfunded_draft"
}
```

## Proof Task: Verified Invite-Code Example (app install + referral code)

Use this shape when workers install an app through your referral link and prove
completion with a code or account email. Three optional powers make the proof
reviewable at scale:

- `proofFields[].extractPattern` — case-insensitive regex; the first match
  (capture group 1 if present) becomes the stored value, so workers can paste a
  whole share message and Chesto keeps only the token. No match on a required
  field rejects the submission with the field's `hint`.
- `proofFields[].normalize` (`uppercase` | `lowercase`) + `unique: true` —
  canonical case, then per-task dedupe: the same code or email cannot be
  submitted twice.
- `guideImages[]` — screenshot walkthrough rendered as a numbered visual guide
  on the task page. Upload each screenshot first via
  `POST /api/action-contracts/example-image` (multipart field `image`, 5MB max)
  and use the returned URL. Display-only; does not count against the 5
  proof-item cap.
- `accountRequirements` — X account-quality gate on any task type. Pass `{}`
  for platform defaults (240-day age, 50 followers, 30 following, 300 posts);
  workers must link a qualifying X account before submitting.

```json
{
  "actionType": "manual_action",
  "title": "Install AppName and submit your invite code",
  "targetUrl": "https://your.referral/link",
  "instructions": "Install the app via the task link, sign up, complete one action, then copy your share text and submit it with your signup email.",
  "rewardUsdc": 0.2,
  "maxCompletions": 100,
  "fundingMode": "unfunded_draft",
  "accountRequirements": {},
  "proofFields": [
    {
      "key": "signup_email",
      "label": "Account email",
      "type": "email",
      "private": true,
      "unique": true,
      "extractPattern": "[^\\s@]+@[^\\s@]+\\.[A-Za-z]{2,}",
      "normalize": "lowercase"
    },
    {
      "key": "invite_code",
      "label": "Your invite code (paste the copied share text)",
      "type": "textarea",
      "private": true,
      "unique": true,
      "hint": "Tap share in the app and paste everything here.",
      "extractPattern": "CODE2026_[A-Z0-9]+",
      "normalize": "uppercase"
    }
  ],
  "guideImages": [
    { "url": "https://.../step-1.jpg", "caption": "1. Install the app from the task link" },
    { "url": "https://.../step-2.jpg", "caption": "2. Sign up with your email" },
    { "url": "https://.../step-3.jpg", "caption": "3. Complete the action and copy your share text" }
  ]
}
```

## Only Invited People

Use `actors[]` with any task type when only named people should receive private
task rooms. This works for KOLs, contractors, partners, reviewers, advisors, or
any specific person.

```json
{
  "actionType": "manual_action",
  "title": "GLM launch private creator brief",
  "instructions": [
    "Review the launch brief",
    "Publish the agreed post",
    "Submit the live post URL"
  ],
  "actors": [
    {
      "name": "Alice Creator",
      "handle": "@alice",
      "rewardUsdc": 300
    },
    {
      "name": "Bob Research",
      "handle": "@bob",
      "rewardUsdc": 200
    }
  ],
  "proofFields": [
    {
      "key": "post_url",
      "label": "Live post URL",
      "type": "url",
      "required": true,
      "visibility": "private"
    }
  ],
  "fundingMode": "unfunded_draft"
}
```

Each actor receives a private task link. Public task browsing should not expose
these reserved actor rooms.

## Activation

Preview/create returns the required budget. Activate only after the publisher
confirms the exact budget:

```http
POST /api/action-contracts/:contractId/activate
Content-Type: application/json
Authorization: Bearer chesto_sk_...
```

```json
{
  "confirmBudgetUsdc": 200
}
```

Activation freezes escrow and publishes eligible child tasks. Drafts remain
inactive until this explicit call.

## Review Modes

- `x_follow`: auto-approved when the X follow check and account requirements pass.
- `x_reply`: auto-approved when the submitted reply URL belongs to the worker and replies to the required parent post.
- `x_like` and `x_repost`: shown as ordered worker steps anchored by follow or reply verification.
- `manual_action`: system or publisher review before payout.
- Only invited people: uses the underlying task review rule, but the room is private to the invited actor.

## Invariants

- Web and agent publishing must use `/api/action-contracts`.
- New tasks are inactive drafts first.
- Public legacy publish endpoints should not create new tasks.
- Do not advertise or build new publishing flows through MCP.
- Do not create one-off templates for every complex task; compose `requirements[]`.
