{
  "protocolVersion": "0.3.0",
  "name": "Chesto",
  "description": "Human Action API for AI agents and product teams: the REST-first Post Task API turns real human actions into goals, steps, proof, review rules, payment, and records. An agent can call any API, but it cannot truly follow or reply from an aged, real X account, nor can it complete private real-world proof work as a specific person. Chesto dispatches that work to verified humans or named assignees, verifies or reviews completion, and settles USDC on Base without manual payment ops (pay only for work that passes; unused budget refundable). Hire via REST with two task types: Social action and Proof task. Product/app tests, signup/register, public proof, and custom work are Proof task use cases, not separate task types. Use actors[] when only invited people should complete it.",
  "url": "https://chesto.ai/api/agent",
  "preferredTransport": "HTTP+JSON",
  "version": "1.0.0",
  "provider": {
    "organization": "Chesto",
    "url": "https://chesto.ai"
  },
  "iconUrl": "https://chesto.ai/icon.png",
  "documentationUrl": "https://chesto.ai/api/agent/docs",
  "capabilities": {
    "streaming": false,
    "pushNotifications": false,
    "stateTransitionHistory": false
  },
  "defaultInputModes": [
    "application/json"
  ],
  "defaultOutputModes": [
    "application/json"
  ],
  "securitySchemes": {
    "apiKey": {
      "type": "http",
      "scheme": "bearer",
      "description": "Bearer token issued at POST /api/agent/register (format: chesto_sk_...). Required on all authenticated endpoints."
    }
  },
  "security": [
    {
      "apiKey": []
    }
  ],
  "skills": [
    {
      "id": "post-social-action-task",
      "name": "Post social action task",
      "description": "Create an inactive Social action Action Contract draft for X followers or engagement. Follow and reply are the auto-verification anchors; like and repost can be ordered steps anchored by follow or reply.",
      "tags": [
        "human-action-api",
        "action-contract",
        "publish",
        "actions",
        "x",
        "twitter",
        "auto-verification"
      ],
      "examples": [
        "POST /api/action-contracts/preview",
        "POST /api/action-contracts"
      ],
      "inputModes": [
        "application/json"
      ],
      "outputModes": [
        "application/json"
      ]
    },
    {
      "id": "post-proof-task",
      "name": "Post proof task",
      "description": "Create an inactive Proof task Action Contract draft for product/app tests, signup/register, browser-extension first-open verification, public proof, private proof, or custom work.",
      "tags": [
        "human-action-api",
        "action-contract",
        "publish",
        "actions",
        "proof",
        "product",
        "app",
        "browser-extension",
        "custom",
        "invite",
        "task-room"
      ],
      "examples": [
        "POST /api/action-contracts/preview",
        "POST /api/action-contracts"
      ],
      "inputModes": [
        "application/json"
      ],
      "outputModes": [
        "application/json"
      ]
    },
    {
      "id": "discover-verified-humans",
      "name": "Discover verified humans",
      "description": "Find opt-in verified humans and their published hireable capabilities. Use capabilities=1 for the hireable marketplace: default returns random published callable APIs grouped by owner, /directory/stats returns total callable API counts, and q searches capability title/description plus name/handle. Then dispatch a private task via Post Task with actors:[\"handle\"], sourceCapabilityId, or callHuman:{handle,capability}. Every eligible human also has two system-default base skills — \"ask\" ($0.50: put any question to a verified human, get a grounded answer + show-your-work image) and \"human-eyes\" ($0.50: open a link, answer with what they saw + a screenshot) — callable via callHuman even if they never published anything.",
      "tags": [
        "discover",
        "humans",
        "directory",
        "card",
        "capabilities",
        "targeting",
        "actors"
      ],
      "examples": [
        "GET /api/users/directory?capabilities=1&limit=10",
        "GET /api/users/directory/stats?capabilities=1",
        "GET /api/users/directory?capabilities=1&q=reply",
        "GET /api/users/card/{uid}",
        "GET /api/users/{uid}/capabilities"
      ],
      "inputModes": [
        "application/json"
      ],
      "outputModes": [
        "application/json"
      ]
    }
  ],
  "x-chesto-marketplace": {
    "thesis": "AI agents and product teams call real human actions through one REST Post Task API: Social action or Proof task, for anyone on Chesto or only invited people.",
    "executedBy": [
      "verified-humans",
      "named-assignees"
    ],
    "supportedPlatforms": [
      "x",
      "browser_extension",
      "custom"
    ],
    "supportedActions": [
      "x_follow",
      "x_reply",
      "browser_extension_first_open",
      "manual_action",
      "private_assignment"
    ],
    "settlement": {
      "currency": "USDC",
      "network": "Base",
      "rail": "FluxaPay",
      "withdrawalFeeUsdc": 0,
      "minWithdrawalUsdc": 0.01
    },
    "onboarding": {
      "register": "POST https://chesto.ai/api/agent/register",
      "authHeader": "Authorization: Bearer chesto_sk_...",
      "previewTask": "POST https://chesto.ai/api/action-contracts/preview",
      "createTaskGroup": "POST https://chesto.ai/api/action-contracts",
      "listTaskGroups": "GET https://chesto.ai/api/action-contracts",
      "activateTaskGroup": "POST https://chesto.ai/api/action-contracts/{contractId}/activate",
      "skillDoc": "https://chesto.ai/skill.md",
      "llmsTxt": "https://chesto.ai/llms.txt",
      "discover": "https://chesto.ai/api/agent/discover",
      "humanSite": "https://chesto.ai"
    },
    "postTaskApi": {
      "endpoint": "POST https://chesto.ai/api/action-contracts",
      "previewEndpoint": "POST https://chesto.ai/api/action-contracts/preview",
      "capabilitiesEndpoint": "GET https://chesto.ai/api/action-contracts/capabilities",
      "reportEndpoint": "GET https://chesto.ai/api/action-contracts/{contractId}/report",
      "status": "Creates inactive Action Contract drafts. Use fundingMode=\"unfunded_draft\" to create first and freeze escrow on activation.",
      "activationBody": {
        "confirmBudgetUsdc": "exact requiredEscrowUsdc from preview/create"
      },
      "endpoints": {
        "capabilities": "GET /api/action-contracts/capabilities",
        "publisherPolicy": "GET /api/action-contracts/publisher-policy - authenticated publisher-specific X Social launch floors. Account overrides are applied automatically; clients cannot request a bypass.",
        "preview": "POST /api/action-contracts/preview",
        "create": "POST /api/action-contracts",
        "list": "GET /api/action-contracts - owned Actions by default. Use ?scope=shared for Actions another owner shared with the authenticated user; ?status=open|active|draft|paused|ended|review; and ?sort=date_desc|date_asc|amount_desc|amount_asc.",
        "latestCompletions": "GET /api/action-contracts/latest/completions - one-call JSON for the latest published Action completion list. Returns contractId, contract summary, count, submissions[].worker.handle, proofUrls, proofLinks, images, fields, rewardUsdc, submittedAt, reviewedAt. Optional ?status=completed|approved|pending|rejected|needs_changes and ?actionStatus=published|active|paused|settled|cancelled|draft|all.",
        "latestCompletionsCsv": "GET /api/action-contracts/latest/completions.csv - one-call CSV for the latest published Action approved/pending_unlock worker rows.",
        "detail": "GET /api/action-contracts/{contractId}",
        "members": "GET /api/action-contracts/{contractId}/members - Owner-only active members and pending invitations.",
        "accessEvents": "GET /api/action-contracts/{contractId}/access-events - Owner-only immutable access history with member, role change, actor type, reason, and time.",
        "memberCandidate": "GET /api/action-contracts/{contractId}/member-candidate?q={exact-email-or-uid-or-handle} - Owner-only, persistently rate-limited exact identity confirmation. Returns public profile identity, a masked email hint, current access, and a short-lived candidateProof; never wallet data or fuzzy results.",
        "addMember": "POST /api/action-contracts/{contractId}/members - Owner sends a pending viewer or manager invitation using memberUserId, role, and the bound candidateProof. It does not grant access.",
        "cancelMemberInvitation": "DELETE /api/action-contracts/{contractId}/invitations/{invitationId} - Owner cancels a pending invitation.",
        "invitations": "GET /api/action-contracts/invitations - authenticated user lists their pending collaboration invitations.",
        "acceptInvitation": "POST /api/action-contracts/invitations/{invitationId}/accept - invited user accepts; only this operation creates Action membership.",
        "declineInvitation": "POST /api/action-contracts/invitations/{invitationId}/decline - invited user declines one invitation.",
        "blockInvitationOwner": "POST /api/action-contracts/invitations/{invitationId}/block - invited user blocks the Owner and closes all pending invitations from them.",
        "reportInvitation": "POST /api/action-contracts/invitations/{invitationId}/report - invited user reports the share as spam, harassment, or other; also blocks that Owner.",
        "accessBlocks": "GET /api/action-contracts/access-blocks and DELETE /api/action-contracts/access-blocks/{ownerUserId} - invited user manages their Owner block list.",
        "adminAccessReports": "GET /api/action-contracts/admin/access-reports and PATCH /api/action-contracts/admin/access-reports/{reportId} - signed platform-admin moderation queue.",
        "adminAddMember": "POST /api/action-contracts/admin/{contractId-or-taskId-or-taskSlug}/members - signed platform-admin break-glass grant. Requires memberUserId, viewer|manager role, and a reason. Writes the real admin-session audit identity and notifies the Owner.",
        "updateMember": "PATCH /api/action-contracts/{contractId}/members/{userId} - Owner changes viewer/manager role.",
        "removeMember": "DELETE /api/action-contracts/{contractId}/members/{userId} - Owner immediately revokes access.",
        "report": "GET /api/action-contracts/{contractId}/report",
        "pointsPoolReport": "GET /api/action-contracts/{contractId}/points-pool/report - publisher report for a points_pool parent task: subtasks, viewer points, eligible users, total eligible points, and estimated capped payouts. Legacy alias: /campaign/report.",
        "updatePointsPool": "PATCH /api/action-contracts/{contractId}/points-pool - update parent task display/economics metadata such as title, description, logo, rewardPoolUsdc, maxPayoutPerUserUsdc, or admin-only fundingMode=system_grant without recompiling child tasks.",
        "addPointsPoolTasks": "POST /api/action-contracts/{contractId}/points-pool/tasks - append future points_pool subtasks, such as Week 2/3/4 optional tasks. Use publishNow=true only when the parent task is already active. Legacy alias: /campaign/tasks.",
        "updatePointsPoolTask": "PATCH /api/action-contracts/{contractId}/points-pool/tasks/{taskId} - update a points_pool subtask title, points, mandatory/optional flag, period, schedule, or live/paused/draft status. Legacy alias: /campaign/tasks/{taskId}.",
        "pointsPoolTaskDetail": "GET /api/tasks/{contractId} - public worker view for a points_pool parent task. Authenticated viewers also receive live points and subtask submission statuses. Legacy alias: GET /api/tasks/campaigns/{contractId}.",
        "reportCsv": "GET /api/action-contracts/{contractId}/report.csv",
        "completionsCsv": "GET /api/action-contracts/{contractId}/completions.csv - minimal publisher export: worker_handle, status, reward_usdc, proof_url, submitted_at, reviewed_at, task_id. Registered extension tasks add provider event, extension ID/version, and receipt timestamps.",
        "submissionsCsv": "GET /api/action-contracts/{contractId}/submissions.csv - publisher/admin reconciliation export. Optional ?status=submitted|approved|rejected|needs_changes filters the export. Includes Chesto public worker UID, configured proof fields as proof_<field_key> columns, and registered-extension reconciliation fields; excludes profile email, wallet data, images, stable device hashes, and verifier secrets.",
        "submissions": "GET /api/action-contracts/{contractId}/submissions — paginated Action member/admin submission data. Returns worker.uid/handle/displayName, configured columns[], submissions[].values, optional submissions[].extensionVerification registered-provider receipt, optional submissions[].xReachSnapshot captured at claim time, full-status totals, and page metadata. summary.needsReply counts conversations where the worker is waiting for an Owner or Manager reply. Optional ?status=submitted|approved|rejected|needs_changes, ?page, and ?limit. Private proof fields stay scoped to authorized Action members/admin; profile email, wallet data, stable device hashes, verifier secrets, and post text are excluded.",
        "viewsReview": "GET /api/action-contracts/{contractId}/views-review — private Action member/admin X-post snapshot curves, reach-policy progress, suggested CPM payout, and human-review signals. Signals are review aids, never worker-facing proof; workers receive only publicReviewNote through their submission view.",
        "claims": "GET /api/action-contracts/{contractId}/claims - Action member paginated claim reservations. Optional ?status=active|finalized|all prevents workflow views from mixing in unrelated history; status=released remains admin-only. Returns public worker identity, timestamps, an optional xReachSnapshot captured at claim time, and a sanitized verificationAttempts summary; excludes expired claims, email, wallet, assigned materials, post text, and private verifier evidence.",
        "activate": "POST /api/action-contracts/{contractId}/activate",
        "updateCapacity": "PATCH /api/action-contracts/{contractId}/capacity",
        "updateBinanceMaterials": "PATCH /api/action-contracts/{contractId}/binance-materials",
        "pause": "POST /api/action-contracts/{contractId}/pause",
        "resume": "POST /api/action-contracts/{contractId}/resume",
        "taskDetail": "GET /api/tasks/{taskId} - worker-facing task detail. Includes verificationPlan with normalized claimAccess, gates, requiredInputs, availability, and the POST /api/submissions dryRun recipe.",
        "claimTaskItem": "POST /api/tasks/{taskId}/claim",
        "replaceActor": "PATCH /api/action-contracts/{contractId}/actors/{taskId}",
        "markAssignmentsContacted": "PATCH /api/action-contracts/{contractId}/private-assignments/contacted",
        "deleteDraft": "DELETE /api/action-contracts/{contractId}",
        "taskRoomResponse": "POST /api/tasks/{taskId}/private-assignment-response",
        "taskRoomMessage": "POST /api/tasks/{taskId}/private-assignment-message",
        "taskRoomNote": "PATCH /api/tasks/{taskId}/private-assignment-note",
        "taskPublisherView": "GET /api/tasks/{taskId}/publisher-view",
        "submitProof": "POST /api/submissions",
        "reviewSubmission": "PUT /api/submissions/{submissionId}/review",
        "reviewRewardStage": "PUT /api/submissions/{submissionId}/stages/{stageKey}/review - pay one due stage, or send decision=void with endFutureStages=true to end this and every later unpaid reward so no future review is needed.",
        "submissionThread": "GET or POST /api/submissions/{submissionId}/messages - publisher/worker thread. Posting a publisher reply clears needsPublisherReply because the latest human message is no longer from the worker.",
        "externalEvidence": "GET /api/submissions/{submissionId}/external-evidence - worker, publisher, or admin reads safe normalized Jina snapshot history. Raw Jina payload and private verification evidence are excluded.",
        "externalEvidenceRaw": "GET /api/submissions/{submissionId}/external-evidence/{snapshotId}/raw - admin-only exact stored Jina response for debugging and extractor audits.",
        "refreshExternalEvidence": "POST /api/submissions/{submissionId}/external-evidence/refresh - worker, publisher, or admin runs one explicit Jina check. Configured Trustpilot staged tasks also keep evidence-only daily snapshots while later stages remain open.",
        "previewInitialReward": "POST /api/submissions/auto-initial-review/preview - publisher/admin read-only Jina preview for a configured task and Trustpilot confirmation URL. Returns every criterion, historical duplicate status, and wouldAutoPay; creates no submission and pays nothing.",
        "retryInitialReward": "POST /api/submissions/{submissionId}/auto-initial-review - worker, publisher, or admin retries the configured Jina first-stage check after cooldown. It can pay only the delayDays=0 stage; later stages remain manual.",
        "configureInitialReward": "PUT /api/admin/initial-reward-automation/action-contracts/{contractId}/trustpilot - platform-admin only. Enables/disables the fixed Jina policy and synchronizes the Action, child Task, proof instructions, and description. Requires an idempotency key and reason.",
        "trustpilotStageEvidenceQueue": "GET /api/admin/initial-reward-automation/trustpilot-stage-evidence?taskId={taskId} - platform-admin read-only queue preview; calls no external provider and moves no money.",
        "runTrustpilotStageEvidence": "POST /api/admin/initial-reward-automation/trustpilot-stage-evidence/run - platform-admin runs the same evidence-only Jina snapshot service as the scheduler. Requires an idempotency key; later stages remain manual.",
        "markTaskRoomRead": "PATCH /api/tasks/{taskId}/private-assignment-read"
      },
      "auth": {
        "discovery": "GET /api/action-contracts/capabilities is public.",
        "publisherRequests": "All preview, create, list, detail, report, claims, activate, private-link tracking, replace, and delete calls require Authorization: Bearer <token>.",
        "webToken": "Use the signed-in user JWT from the web app.",
        "agentApiKey": "Use an active Agent API key in the same Authorization header."
      },
      "responseEnvelope": {
        "success": "{ ok: true, data: {...}, api: {...}, next: {...} }",
        "compatibility": "Legacy top-level fields are preserved while agent-stable data/api/next fields are added."
      },
      "idempotency": {
        "header": "Idempotency-Key",
        "supportedOn": [
          "POST /api/action-contracts",
          "POST /api/action-contracts/{contractId}/activate",
          "PATCH /api/action-contracts/{contractId}/capacity",
          "POST /api/tasks/{taskId}/claim",
          "POST /api/submissions",
          "PUT /api/submissions/{submissionId}/review",
          "PUT /api/submissions/{submissionId}/stages/{stageKey}/review",
          "POST /api/agent/tasks/{taskId}/submit"
        ],
        "retryRule": "Reuse the same key only with the exact same method, path, body, query, and file metadata. A different body returns 409.",
        "replayHeader": "Idempotency-Replayed: true"
      },
      "sandbox": {
        "dryRun": "Set body.dryRun=true or header X-Chesto-Dry-Run: true to validate without creating contracts, tasks, submissions, escrow, rewards, uploads, or review writes.",
        "taskPlan": "Call GET /api/tasks/{taskId} first and read verificationPlan.dryRun to see which gates dryRun will execute and whether claim is required before proof fields unlock.",
        "supportedOn": [
          "POST /api/action-contracts",
          "POST /api/action-contracts/{contractId}/activate",
          "PATCH /api/action-contracts/{contractId}/capacity",
          "POST /api/submissions",
          "PUT /api/submissions/{submissionId}/review",
          "POST /api/agent/tasks/{taskId}/submit"
        ]
      },
      "requestModel": {
        "sourceOfTruth": "requirements[] for social tasks",
        "authoringModel": {
          "primary": "Choose a task type first: Social action or Proof task. Then choose the audience: anyone on Chesto or only invited people. Product/app tests, signup/register, public proof, and custom work are Proof task use cases, not separate system types. Private assignment is an audience shape, not a separate task type.",
          "compatibilityFields": "templateKey and targetUrl are compiled from requirements[] for existing data/UI compatibility.",
          "policyCatalogRole": "Policy catalog only: labels, minimum rewards, review mode, and account requirement presets. It is not an authoring surface."
        },
        "primaryAuthoringModes": [
          {
            "id": "social_action",
            "label": "Social action",
            "actionType": "social_action",
            "audienceShape": "anyoneOnChesto or onlyInvitedPeople",
            "review": "x_follow and x_reply are auto-approved when X verification and account requirements pass. Like and repost are ordered worker steps anchored by follow or reply verification.",
            "useWhen": "You want X followers or X engagement."
          },
          {
            "id": "proof_task",
            "label": "Proof task",
            "actionType": "manual_action",
            "audienceShape": "anyoneOnChesto or onlyInvitedPeople",
            "review": "Worker submits configured proofFields; payout waits for system or publisher review.",
            "useWhen": "You want product/app tests, signups, public proof, or custom work that Chesto cannot auto-verify yet.",
            "proofPresets": [
              "private_proof",
              "public_proof",
              "blank_custom"
            ]
          }
        ],
        "proofTaskPresets": {
          "private_proof": "Submit private account, receipt, result, or feedback proof for review.",
          "public_proof": "Submit a public proof URL for review.",
          "blank_custom": "Start from a blank task brief with one configurable proof field."
        },
        "supportedActionTypes": [
          "social_action",
          "manual_action"
        ],
        "defaultCompletionMode": "after_completion",
        "commonFields": [
          "actionType",
          "title",
          "logo",
          "templateKey=points_pool_campaign + campaign{mode,rewardPoolUsdc,tasks[]} for campaign mode",
          "requirements",
          "gates",
          "proofFields",
          "claimPolicy",
          "workerStake",
          "geoAllowlist",
          "sourceCapabilityId + buyerInputs for a person-specific capability",
          "callHuman{handle,capability} + buyerInputs to call a person by X handle — works for the system-default \"ask\" and \"human-eyes\" skills every eligible human has",
          "instructions",
          "acceptanceCriteria",
          "rewardUsdc or rewardMinUsdc/rewardMaxUsdc",
          "maxCompletions or countries or actors",
          "expiresAt",
          "fundingMode"
        ],
        "adminOnlyFields": {
          "karmaOnly": "Set true with rewardUsdc=0 for an open manual Proof Task that awards the fixed Karma reward without worker USDC escrow."
        },
        "gateCatalog": [
          {
            "id": "binance_square_post",
            "label": "Binance Square post",
            "actionType": "manual_action",
            "inputFields": [
              "proofUrl"
            ],
            "runner": "internal",
            "retryable": true,
            "costLevel": "external_fetch",
            "retrievalMethods": [
              "jina_reader"
            ],
            "configSchema": {
              "allowedDrafts": "1-100 approved text examples. The verifier matches fetched Binance content against any one of them.",
              "minSimilarity": "Default 0.82. Recommended range 0.7-1.",
              "mediaOptions": "0-100 publisher-provided images workers may attach to the Binance post.",
              "requireImage": "When true, the fetched Binance post must expose at least one image.",
              "requirePublishedAfterTaskStart": "Default true.",
              "minFollowers": "Optional claim-time Binance Square follower floor. Requires claimPolicy.mode=required.",
              "uniqueScope": "Default 'task'.",
              "uniqueAuthor": "Default true. Prevents one Binance author from completing the same task multiple times.",
              "uniqueAuthorScope": "Default 'task'. Use 'global' only for platform-wide author uniqueness."
            },
            "evidenceSchema": [
              "platform",
              "contentId",
              "canonicalUrl",
              "author",
              "authorName",
              "publishedAt",
              "contentText",
              "retrieval.method"
            ]
          },
          {
            "id": "browser_extension_first_open",
            "label": "Chrome extension first open",
            "actionType": "manual_action",
            "inputFields": [],
            "runner": "signed_partner_webhook",
            "retryable": true,
            "costLevel": "partner_callback",
            "retrievalMethods": [
              "chrome_external_messaging",
              "signed_webhook"
            ],
            "configSchema": {
              "providerKey": "Admin-registered extension verification provider key.",
              "extensionId": "Official 32-character Chrome extension id.",
              "chromeStoreUrl": "Official Chrome Web Store https URL.",
              "minVersion": "Minimum accepted Chrome manifest version, for example 1.2.0.",
              "eventName": "Default 'extension_first_open'. Must match the provider registration.",
              "requireNewInstall": "Default true. Rejects installs and first opens predating the Chesto attempt.",
              "claimTtlMinutes": "Default 30; range 5-120."
            },
            "evidenceSchema": [
              "providerKey",
              "eventId",
              "extensionId",
              "extensionVersion",
              "installIdHash",
              "installedAt",
              "firstOpenedAt"
            ]
          },
          {
            "id": "discord_guild",
            "label": "Discord server join",
            "actionType": "manual_action",
            "inputFields": [],
            "runner": "internal",
            "retryable": true,
            "costLevel": "external_fetch",
            "retrievalMethods": [
              "discord_bot_rest"
            ],
            "configSchema": {
              "discordGuildId": "Required Discord server (guild) snowflake id, 17-20 digits.",
              "discordInviteUrl": "Required permanent invite, e.g. https://discord.gg/<code>. Shown as the join button.",
              "discordGuildName": "Optional display name for the server."
            },
            "evidenceSchema": [
              "guildId"
            ],
            "prerequisites": [
              "Guild is registered via POST /api/admin/discord/whitelist before activation.",
              "The Chesto verification bot has been invited to the guild and BotGuard flipped the entry to active."
            ]
          }
        ],
        "extensionVerification": {
          "providerSetup": "POST /api/action-verifications/providers - platform-admin only; returns the webhook secret once.",
          "workerAttempt": "POST /api/action-verifications/extension/attempts - authenticated worker; body {taskId, inviteToken?}. An inactive invite-only sandbox may also send {extensionId, extensionVersion} to target a locally loaded build; live tasks reject those overrides.",
          "attemptStatus": "GET /api/action-verifications/extension/attempts/{attemptId} - authenticated attempt owner.",
          "providerWebhook": "POST /api/action-verifications/webhooks/{providerKey} - raw JSON signed by the registered provider server.",
          "note": "Provider registration and publisher authorization must match the gate snapshot before Action activation."
        },
        "jsonSchema": {
          "$schema": "https://json-schema.org/draft/2020-12/schema",
          "title": "Chesto Post Task request",
          "type": "object",
          "required": [
            "actionType",
            "title"
          ],
          "additionalProperties": true,
          "properties": {
            "actionType": {
              "type": "string",
              "enum": [
                "social_action",
                "manual_action"
              ]
            },
            "action_type": {
              "type": "string",
              "enum": [
                "social_action",
                "manual_action"
              ],
              "description": "Alias for actionType."
            },
            "sourceCapabilityId": {
              "type": "string",
              "description": "Published UserCapability id from GET /api/users/{uid}/capabilities. Compiles into a private actor-targeted Action for that person."
            },
            "source_capability_id": {
              "type": "string",
              "description": "Alias for sourceCapabilityId."
            },
            "callHuman": {
              "type": "object",
              "description": "Call a person by X handle + capability slug instead of an id. Every eligible Chesto human has two system-default slugs: \"ask\" ($0.50: any question → a grounded human answer + a show-your-work image) and \"human-eyes\" ($0.50: open a link, answer with what they saw + screenshot). Calls are prepaid: the listed price is frozen from your balance at call time and the task goes live immediately — insufficient balance returns 422 and creates nothing. Undelivered calls auto-refund after 72h; delivered proof auto-approves if you do not review within 72h. Example: { \"handle\": \"jinyuanwang\", \"capability\": \"ask\" }.",
              "properties": {
                "handle": {
                  "type": "string",
                  "description": "X handle of the human to call, with or without @."
                },
                "capability": {
                  "type": "string",
                  "description": "Capability slug, e.g. \"ask\" or \"human-eyes\"."
                }
              },
              "required": [
                "handle",
                "capability"
              ]
            },
            "call_human": {
              "type": "object",
              "description": "Alias for callHuman."
            },
            "buyerInputs": {
              "type": "object",
              "additionalProperties": {
                "type": "string"
              },
              "description": "Values for the selected capability buyerInputs, such as { \"targetUrl\": \"https://...\" }."
            },
            "buyer_inputs": {
              "type": "object",
              "additionalProperties": {
                "type": "string"
              },
              "description": "Alias for buyerInputs."
            },
            "title": {
              "type": "string",
              "minLength": 2,
              "maxLength": 140
            },
            "taskSlug": {
              "type": "string",
              "pattern": "^[a-z0-9][a-z0-9_-]{1,80}$",
              "description": "Optional readable /task/{slug} link for an Action that compiles to exactly one child task. Must be globally unique."
            },
            "task_slug": {
              "type": "string",
              "description": "Alias for taskSlug."
            },
            "intentText": {
              "type": "string",
              "maxLength": 1000
            },
            "intent_text": {
              "type": "string",
              "maxLength": 1000,
              "description": "Alias for intentText."
            },
            "logo": {
              "type": "string",
              "description": "Optional task avatar as an https:// URL or a site-relative /path."
            },
            "taskLogo": {
              "type": "string",
              "description": "Alias for logo."
            },
            "task_logo": {
              "type": "string",
              "description": "Alias for logo."
            },
            "targetUrl": {
              "type": "string",
              "description": "Compatibility field. For social tasks, prefer requirements[].targetUrl."
            },
            "url": {
              "type": "string",
              "description": "Alias for top-level targetUrl."
            },
            "link": {
              "type": "string",
              "description": "Alias for top-level targetUrl."
            },
            "actionUrl": {
              "type": "string",
              "description": "Alias for top-level targetUrl."
            },
            "action_url": {
              "type": "string",
              "description": "Alias for top-level targetUrl."
            },
            "productUrl": {
              "type": "string",
              "description": "Alias for top-level targetUrl."
            },
            "product_url": {
              "type": "string",
              "description": "Alias for top-level targetUrl."
            },
            "geoAllowlist": {
              "type": "array",
              "uniqueItems": true,
              "maxItems": 249,
              "description": "Optional ISO 3166-1 alpha-2 country codes allowed to see, claim, and submit the task. Unknown IP country is rejected. Empty or omitted means global.",
              "items": {
                "type": "string",
                "pattern": "^[A-Za-z]{2}$"
              }
            },
            "geo_allowlist": {
              "type": "array",
              "description": "Alias for geoAllowlist.",
              "items": {
                "type": "string"
              }
            },
            "requirements": {
              "type": "array",
              "description": "Source of truth for social tasks. Compose follow verification, ordered engagement steps, and at most one reply proof here.",
              "items": {
                "type": "object",
                "required": [
                  "type"
                ],
                "additionalProperties": false,
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "x_follow",
                      "x_like",
                      "x_repost",
                      "x_reply"
                    ]
                  },
                  "targetUrl": {
                    "type": "string"
                  },
                  "url": {
                    "type": "string",
                    "description": "Alias for targetUrl."
                  },
                  "link": {
                    "type": "string",
                    "description": "Alias for targetUrl."
                  },
                  "tweetUrl": {
                    "type": "string",
                    "description": "Alias for targetUrl when targeting an X post."
                  },
                  "tweet_url": {
                    "type": "string",
                    "description": "Alias for targetUrl when targeting an X post."
                  },
                  "profileUrl": {
                    "type": "string",
                    "description": "Alias for targetUrl when targeting an X profile."
                  },
                  "profile_url": {
                    "type": "string",
                    "description": "Alias for targetUrl when targeting an X profile."
                  },
                  "handle": {
                    "type": "string"
                  },
                  "target": {
                    "type": "object",
                    "description": "Agent-friendly alias. For x_follow use target.handle; for x_like/x_repost/x_reply use target.url.",
                    "additionalProperties": true,
                    "properties": {
                      "handle": {
                        "type": "string"
                      },
                      "username": {
                        "type": "string"
                      },
                      "url": {
                        "type": "string"
                      },
                      "link": {
                        "type": "string"
                      },
                      "tweetUrl": {
                        "type": "string"
                      },
                      "tweet_url": {
                        "type": "string"
                      },
                      "profileUrl": {
                        "type": "string"
                      },
                      "profile_url": {
                        "type": "string"
                      }
                    }
                  },
                  "tweetId": {
                    "type": "string"
                  },
                  "tweet_id": {
                    "type": "string",
                    "description": "Alias for tweetId."
                  },
                  "targetMode": {
                    "type": "string",
                    "enum": [
                      "latest",
                      "specific"
                    ],
                    "description": "For x_like/x_repost, latest uses the newest post from targetUrl profile."
                  },
                  "target_mode": {
                    "type": "string",
                    "enum": [
                      "latest",
                      "specific"
                    ],
                    "description": "Alias for targetMode."
                  },
                  "verify": {
                    "type": "boolean"
                  }
                }
              }
            },
            "proofFields": {
              "type": "array",
              "description": "Required proof fields for manual or external proof Actions.",
              "items": {
                "type": "object",
                "required": [
                  "key",
                  "label"
                ],
                "additionalProperties": true,
                "properties": {
                  "key": {
                    "type": "string",
                    "pattern": "^[a-z0-9_]+$"
                  },
                  "label": {
                    "type": "string"
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "text",
                      "url",
                      "textarea",
                      "number",
                      "email"
                    ]
                  },
                  "proofType": {
                    "type": "string"
                  },
                  "private": {
                    "type": "boolean"
                  },
                  "unique": {
                    "type": "boolean",
                    "description": "Reject a value already submitted on this task (dedupe runs on the extracted token when extractPattern is set)."
                  },
                  "required": {
                    "type": "boolean"
                  },
                  "hint": {
                    "type": "string"
                  },
                  "extractPattern": {
                    "type": "string",
                    "description": "Regex (case-insensitive) applied to the submitted value; the first match (capture group 1 if present) becomes the stored value. Lets workers paste surrounding text around a code. No match on a required field rejects the submission."
                  },
                  "normalize": {
                    "type": "string",
                    "enum": [
                      "uppercase",
                      "lowercase"
                    ],
                    "description": "Canonical case applied after extractPattern, so unique dedupe is case-insensitive."
                  },
                  "urlPrefix": {
                    "type": "string",
                    "description": "Required link prefix, e.g. 'google.com/maps/place'. Protocol and www. are ignored on both sides; a submitted link that does not start with this prefix is rejected."
                  },
                  "linkUrl": {
                    "type": "string",
                    "description": "Optional helper https URL rendered as a clickable link next to the field title (e.g. where the worker performs the action)."
                  },
                  "blockedValues": {
                    "type": "array",
                    "maxItems": 200,
                    "items": {
                      "type": "string"
                    },
                    "description": "Values rejected as already used (protocol, www. and trailing slash ignored when comparing links)."
                  },
                  "contentCheck": {
                    "type": "object",
                    "description": "Automatic link-content rule: the submitted URL is fetched via Jina reader and must satisfy the declared terms before the field is accepted. Declarative only.",
                    "properties": {
                      "enabled": {
                        "type": "boolean"
                      },
                      "mustContain": {
                        "type": "array",
                        "maxItems": 20,
                        "items": {
                          "type": "string"
                        },
                        "description": "Every term must appear in the fetched page text (case-insensitive)."
                      },
                      "anyOf": {
                        "type": "array",
                        "maxItems": 20,
                        "items": {
                          "type": "string"
                        },
                        "description": "At least one term must appear."
                      },
                      "minChars": {
                        "type": "integer",
                        "description": "Minimum fetched-page text length."
                      }
                    }
                  }
                }
              }
            },
            "proof_fields": {
              "type": "array",
              "description": "Alias for proofFields."
            },
            "guideImages": {
              "type": "array",
              "maxItems": 8,
              "description": "Visual step-by-step walkthrough shown on the task page (display-only; does not count against the 5 proof-item cap). Upload screenshots via POST /api/action-contracts/example-image, then pass { url, caption } per step.",
              "items": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "https URL returned by the example-image upload endpoint."
                  },
                  "caption": {
                    "type": "string",
                    "description": "One-line explanation of the step (max 200 chars)."
                  },
                  "linkUrl": {
                    "type": "string",
                    "description": "Optional http/https action link shown below this visual-guide step."
                  }
                }
              }
            },
            "guide_images": {
              "type": "array",
              "description": "Alias for guideImages."
            },
            "accountRequirements": {
              "type": "object",
              "description": "X account-quality gate for the worker. Always applied to social Actions with x_follow; proof (manual) Actions opt in by passing this object — {} uses platform defaults (account age 240d, 50 followers, 30 following, 300 posts). Workers must link X and meet these to submit.",
              "properties": {
                "minAgeDays": {
                  "type": "number"
                },
                "minFollowers": {
                  "type": "number"
                },
                "minFollowing": {
                  "type": "number"
                },
                "minTweets": {
                  "type": "number"
                },
                "requireBlueBadge": {
                  "type": "boolean"
                },
                "minRecentOriginalViews": {
                  "type": "number",
                  "description": "Reach gate: median view count of the worker's last 20 original posts (replies/reposts excluded) must reach this. 0 disables. Checked live at claim and submit."
                }
              }
            },
            "gates": {
              "type": "array",
              "description": "System-supported automatic verification gates. binance_square_post verifies a public URL; browser_extension_first_open verifies a one-time claim through a registered partner webhook; discord_guild verifies server membership through the Chesto bot.",
              "maxItems": 1,
              "items": {
                "type": "object",
                "required": [
                  "id"
                ],
                "additionalProperties": true,
                "properties": {
                  "id": {
                    "type": "string",
                    "enum": [
                      "binance_square_post",
                      "browser_extension_first_open",
                      "discord_guild"
                    ]
                  },
                  "gateId": {
                    "type": "string",
                    "enum": [
                      "binance_square_post",
                      "browser_extension_first_open",
                      "discord_guild"
                    ],
                    "description": "Alias for id."
                  },
                  "config": {
                    "type": "object",
                    "additionalProperties": true,
                    "properties": {
                      "allowedDrafts": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "description": "Required approved text examples. Workers choose one, and the verifier matches fetched Binance post content against any one example.",
                        "items": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "object",
                              "required": [
                                "text"
                              ],
                              "additionalProperties": true,
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "title": {
                                  "type": "string"
                                },
                                "text": {
                                  "type": "string"
                                }
                              }
                            }
                          ]
                        }
                      },
                      "mediaOptions": {
                        "type": "array",
                        "maxItems": 100,
                        "description": "Publisher-provided image options workers can attach to the Binance Square post.",
                        "items": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "object",
                              "required": [
                                "imageUrl"
                              ],
                              "additionalProperties": true,
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "label": {
                                  "type": "string"
                                },
                                "imageUrl": {
                                  "type": "string"
                                }
                              }
                            }
                          ]
                        }
                      },
                      "minSimilarity": {
                        "type": "number",
                        "minimum": 0.5,
                        "maximum": 1
                      },
                      "requireImage": {
                        "type": "boolean"
                      },
                      "requirePublishedAfterTaskStart": {
                        "type": "boolean"
                      },
                      "minFollowers": {
                        "type": "integer",
                        "minimum": 0,
                        "description": "Claim-time Binance Square follower floor. Requires claimPolicy.mode=required."
                      },
                      "requiredAuthors": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "uniqueAuthor": {
                        "type": "boolean",
                        "description": "Default true. Prevents one Binance author from completing the same task multiple times."
                      },
                      "uniqueAuthorScope": {
                        "type": "string",
                        "enum": [
                          "task",
                          "global"
                        ],
                        "description": "Default task."
                      },
                      "providerKey": {
                        "type": "string",
                        "description": "Admin-registered extension verification provider key."
                      },
                      "extensionName": {
                        "type": "string",
                        "description": "Worker-facing extension name used in installation instructions."
                      },
                      "extensionId": {
                        "type": "string",
                        "pattern": "^[a-p]{32}$",
                        "description": "Official Chrome extension id."
                      },
                      "chromeStoreUrl": {
                        "type": "string",
                        "description": "Official Chrome Web Store URL."
                      },
                      "minVersion": {
                        "type": "string",
                        "description": "Minimum Chrome manifest version, for example 1.2.0."
                      },
                      "eventName": {
                        "type": "string",
                        "description": "Signed provider event. Default extension_first_open."
                      },
                      "requireNewInstall": {
                        "type": "boolean",
                        "description": "Default true; reject installs predating the Chesto attempt."
                      },
                      "claimTtlMinutes": {
                        "type": "integer",
                        "minimum": 5,
                        "maximum": 120,
                        "description": "One-time claim validity. Default 30 minutes."
                      },
                      "discordGuildId": {
                        "type": "string",
                        "pattern": "^\\d{17,20}$",
                        "description": "discord_guild: Discord server (guild) snowflake id."
                      },
                      "discordInviteUrl": {
                        "type": "string",
                        "description": "discord_guild: permanent invite, https://discord.gg/<code>."
                      },
                      "discordGuildName": {
                        "type": "string",
                        "description": "discord_guild: optional server display name."
                      }
                    }
                  }
                }
              }
            },
            "proofGates": {
              "type": "array",
              "description": "Alias for gates."
            },
            "proof_gates": {
              "type": "array",
              "description": "Alias for gates."
            },
            "requiredImages": {
              "type": "array",
              "description": "Named screenshot/image upload slots the worker must (or may) submit as proof. Custom (manual_action) tasks only. Counts toward the combined 5-item proof cap (text + URL + image).",
              "maxItems": 5,
              "items": {
                "type": "object",
                "required": [
                  "label"
                ],
                "additionalProperties": false,
                "properties": {
                  "label": {
                    "type": "string",
                    "description": "What this image should show, e.g. \"Profile screenshot\"."
                  },
                  "description": {
                    "type": "string",
                    "description": "Optional extra guidance for the worker."
                  },
                  "required": {
                    "type": "boolean",
                    "description": "Whether this image is mandatory. Defaults to true."
                  }
                }
              }
            },
            "required_images": {
              "type": "array",
              "description": "Alias for requiredImages."
            },
            "claimPolicy": {
              "type": "object",
              "description": "Optional assignment gate. mode=required means workers must POST /api/tasks/{taskId}/claim before task-specific text/images are revealed. Active claims expire after ttlMinutes so unused text returns to the pool.",
              "additionalProperties": false,
              "properties": {
                "mode": {
                  "type": "string",
                  "enum": [
                    "none",
                    "required"
                  ],
                  "description": "Canonical claim mode. Use required for unique text/image assignment; omit or use none for normal tasks."
                },
                "enabled": {
                  "type": "boolean",
                  "description": "Legacy alias. true maps to mode=required."
                },
                "requireClaimBeforeSubmit": {
                  "type": "boolean",
                  "description": "Legacy flag. Does not enable claim by itself."
                },
                "ttlMinutes": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 1440,
                  "description": "Defaults to 20."
                },
                "lockMaterials": {
                  "type": "boolean",
                  "description": "Default true: title/brief/materials hidden until claim. false = seat-only claim: the brief stays public and Claim only reserves one of the task seats."
                },
                "publicPreview": {
                  "type": "object",
                  "additionalProperties": false,
                  "description": "Publisher-defined pre-claim view for sensitive tasks (client account, tracked links stay hidden). Shown instead of the generic locked placeholder; the full brief unlocks after claim.",
                  "properties": {
                    "title": {
                      "type": "string",
                      "maxLength": 200,
                      "description": "Public teaser title, e.g. \"Post 1 original tweet for a DeFi perp DEX\"."
                    },
                    "brief": {
                      "type": "string",
                      "maxLength": 2000,
                      "description": "Public teaser brief: what kind of work, eligibility, payout condition. No client-identifying details."
                    }
                  }
                },
                "assignmentMode": {
                  "type": "string",
                  "enum": [
                    "random_independent",
                    "paired_by_index"
                  ],
                  "description": "How text and image assignments are selected. random_independent picks a random text and random image. paired_by_index binds textPool[n] to imagePool[n]."
                },
                "textPool": {
                  "type": "array",
                  "maxItems": 500,
                  "items": {
                    "type": "string"
                  },
                  "description": "Required unique text assignments. Example: 41 post/comment variants, one per worker claim."
                },
                "imagePool": {
                  "type": "array",
                  "maxItems": 100,
                  "items": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "object",
                        "required": [
                          "imageUrl"
                        ],
                        "additionalProperties": false,
                        "properties": {
                          "label": {
                            "type": "string"
                          },
                          "imageUrl": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          }
                        }
                      }
                    ]
                  },
                  "description": "Reference images revealed only after claim. Selection follows assignmentMode."
                }
              }
            },
            "claim_policy": {
              "type": "object",
              "description": "Alias for claimPolicy."
            },
            "workerStake": {
              "type": "object",
              "additionalProperties": false,
              "description": "Optional refundable worker USDC stake. With claimPolicy.mode=required, Claim locks the stake immediately; proof submission transfers the same lock to the Submission, approval refunds it, and claim expiry forfeits it. Without a claim gate, the stake is locked at proof submission.",
              "properties": {
                "enabled": {
                  "type": "boolean"
                },
                "amountUsdc": {
                  "type": "number",
                  "minimum": 0.01,
                  "maximum": 100
                },
                "refundPolicy": {
                  "type": "string",
                  "enum": [
                    "approved_or_honest_reject",
                    "approved_only"
                  ],
                  "description": "approved_only returns the stake only after proof approval. Claim expiry always forfeits a claim-time stake."
                },
                "forfeitPolicy": {
                  "type": "string",
                  "readOnly": true,
                  "enum": [
                    "fraud_or_spam_only",
                    "claim_expiry_or_unapproved"
                  ],
                  "description": "Derived from refundPolicy and returned in previews, claims, and submissions."
                },
                "purpose": {
                  "type": "string",
                  "description": "Short ledger purpose; defaults to reserve_slot."
                }
              }
            },
            "worker_stake": {
              "type": "object",
              "description": "Alias for workerStake."
            },
            "instructions": {
              "type": "string"
            },
            "acceptanceCriteria": {
              "type": "string"
            },
            "acceptance_criteria": {
              "type": "string",
              "description": "Alias for acceptanceCriteria."
            },
            "rewardUsdc": {
              "type": "number",
              "minimum": 0,
              "description": "Reward per approved proof. Public publishers must use at least 0.1 USDC; zero is reserved for admin-authorized karmaOnly Proof Tasks."
            },
            "reward_usdc": {
              "type": "number",
              "minimum": 0,
              "description": "Alias for rewardUsdc."
            },
            "karmaOnly": {
              "type": "boolean",
              "description": "Admin-only Proof Task mode. Requires actionType=manual_action, rewardUsdc=0, a public audience, and fundingMode=unfunded_draft. Approval issues the fixed Karma reward without worker USDC escrow."
            },
            "karma_only": {
              "type": "boolean",
              "description": "Alias for karmaOnly."
            },
            "rewardMinUsdc": {
              "type": "number",
              "minimum": 0.1
            },
            "reward_min_usdc": {
              "type": "number",
              "minimum": 0.1,
              "description": "Alias for rewardMinUsdc."
            },
            "rewardMaxUsdc": {
              "type": "number",
              "minimum": 0.1
            },
            "reward_max_usdc": {
              "type": "number",
              "minimum": 0.1,
              "description": "Alias for rewardMaxUsdc."
            },
            "maxCompletions": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000
            },
            "max_completions": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000,
              "description": "Alias for maxCompletions."
            },
            "dailyLimit": {
              "type": "integer",
              "minimum": 0
            },
            "daily_limit": {
              "type": "integer",
              "minimum": 0,
              "description": "Alias for dailyLimit."
            },
            "expiresAt": {
              "type": "string",
              "format": "date-time",
              "description": "Optional hard cutoff. The Action cannot be published, claimed, or submitted after this time."
            },
            "expires_at": {
              "type": "string",
              "format": "date-time",
              "description": "Alias for expiresAt."
            },
            "countries": {
              "type": "array",
              "items": {
                "type": "object",
                "required": [
                  "code",
                  "slots"
                ],
                "properties": {
                  "code": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 2
                  },
                  "slots": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "rewardUsdc": {
                    "type": "number",
                    "minimum": 0.1
                  },
                  "reward_usdc": {
                    "type": "number",
                    "minimum": 0.1,
                    "description": "Alias for rewardUsdc."
                  }
                }
              }
            },
            "actors": {
              "type": "array",
              "items": {
                "type": "object",
                "required": [
                  "platform",
                  "handle",
                  "rewardUsdc"
                ],
                "properties": {
                  "platform": {
                    "type": "string",
                    "enum": [
                      "x"
                    ]
                  },
                  "handle": {
                    "type": "string"
                  },
                  "profileUrl": {
                    "type": "string"
                  },
                  "profile_url": {
                    "type": "string",
                    "description": "Alias for profileUrl."
                  },
                  "rewardUsdc": {
                    "type": "number",
                    "minimum": 0.1
                  },
                  "reward_usdc": {
                    "type": "number",
                    "minimum": 0.1,
                    "description": "Alias for rewardUsdc."
                  }
                }
              }
            },
            "fundingMode": {
              "type": "string",
              "enum": [
                "unfunded_draft",
                "funded_escrow"
              ]
            },
            "funding_mode": {
              "type": "string",
              "enum": [
                "unfunded_draft",
                "funded_escrow"
              ],
              "description": "Alias for fundingMode."
            }
          }
        },
        "fundingModes": {
          "unfunded_draft": "Create real draft URLs and inactive child tasks without freezing USDC.",
          "funded_escrow": "Freeze publisher escrow during draft creation, while child tasks still stay inactive until activation."
        },
        "campaignModes": {
          "points_pool": {
            "templateKey": "points_pool_campaign",
            "purpose": "One marketplace campaign card containing mandatory and optional child tasks. Approved child-task submissions earn points; eligible users split one USDC pool by point weight.",
            "rewardModel": "Parent ActionContract stores rewardPoolUsdc and escrow. Child Tasks carry reward=0 and publishSpec.campaign.points.",
            "supportedTaskKinds": [
              "mandatory_checklist",
              "x_follow",
              "x_like",
              "x_repost",
              "x_reply",
              "telegram_group",
              "discord_guild",
              "manual_proof_url"
            ],
            "marketplaceBehavior": "Only points_pool child tasks are folded into the parent campaign card in /api/tasks. Legacy tasks and normal Action child tasks are unchanged.",
            "publisherEditing": "Use PATCH /api/action-contracts/{contractId}/points-pool/tasks/{taskId} for quick edits to points, mandatory/optional, and child-task pause/resume without touching submissions.",
            "settlement": "GET /api/action-contracts/{contractId}/points-pool/report estimates capped payouts. POST /api/action-contracts/{contractId}/points-pool/settle credits user balances and writes campaign_payout ledger rows after explicit pool confirmation.",
            "example": {
              "templateKey": "points_pool_campaign",
              "title": "Community Quest",
              "fundingMode": "unfunded_draft",
              "campaign": {
                "mode": "points_pool",
                "rewardPoolUsdc": 600,
                "maxPayoutPerUserUsdc": 50,
                "startsAt": "2026-07-03T00:00:00.000Z",
                "endsAt": "2026-07-31T23:59:59.000Z",
                "tasks": [
                  {
                    "key": "mandatory_checklist",
                    "kind": "mandatory_checklist",
                    "title": "Mandatory checklist",
                    "points": 1,
                    "requiredForEligibility": true,
                    "config": {
                      "handle": "brand",
                      "telegramGroupId": "-100...",
                      "telegramGroupInviteUrl": "https://t.me/...",
                      "discordGuildId": "...",
                      "discordInviteUrl": "https://discord.gg/..."
                    }
                  },
                  {
                    "key": "repost_week_1",
                    "kind": "x_repost",
                    "title": "Repost Week 1 campaign tweet",
                    "points": 1,
                    "periodKey": "week_1",
                    "config": {
                      "tweetUrl": "https://x.com/brand/status/123"
                    }
                  },
                  {
                    "key": "submit_week_1",
                    "kind": "manual_proof_url",
                    "title": "Submit Week 1 X post link",
                    "points": 1,
                    "periodKey": "week_1",
                    "config": {
                      "proofPlatform": "x",
                      "requiredText": [
                        "#HappyBDayFour",
                        "#HBD4Meme"
                      ]
                    }
                  }
                ],
                "referralRule": {
                  "enabled": true,
                  "pointsPerInvite": 1,
                  "maxInvitesPerUser": 3
                }
              }
            }
          }
        },
        "audienceShapes": {
          "anyoneOnChesto": {
            "meaning": "Open marketplace task visible to matching Chesto workers.",
            "mapsTo": "maxCompletions or countries"
          },
          "onlyInvitedPeople": {
            "meaning": "Private task rooms for named people, creators, contractors, partners, reviewers, or advisors.",
            "mapsTo": "actors[]"
          },
          "publicCrowd": {
            "maxCompletions": 100,
            "dailyLimit": 0,
            "compatibility": "Backward-compatible alias for anyoneOnChesto."
          },
          "countryCohorts": {
            "countries": [
              {
                "code": "US",
                "slots": 50
              }
            ],
            "compatibility": "Backward-compatible regional form of anyoneOnChesto."
          },
          "privateAssignees": {
            "actors": [
              {
                "platform": "x",
                "handle": "chestoai",
                "rewardUsdc": 25
              }
            ],
            "note": "Backward-compatible alias for onlyInvitedPeople. Use actors[] for KOLs, reviewers, contractors, partners, or any specific person/account."
          },
          "reservedActors": {
            "actors": [
              {
                "platform": "x",
                "handle": "chestoai",
                "rewardUsdc": 25
              }
            ],
            "compatibility": "Backward-compatible alias for privateAssignees."
          }
        },
        "defaultHumanApi": {
          "meaning": "Every eligible Chesto human is callable out of the box — no prior publishing by the person. Two system-default base skills ($0.50, 24h each): \"ask\" is the primitive (put any question to a verified human), \"human-eyes\" is its look-at-a-link preset.",
          "whatYouGet": "ask: a considered written answer grounded in the person's own judgment/experience, plus a show-your-work image. human-eyes: the person opens your link, spends two real minutes, and returns a written first-impression answer plus a screenshot. Proof is reviewed by you before payout.",
          "discover": "GET /api/users/{uid}/capabilities or GET /api/users/card/{uid} — UID is the permanent public identity. Rows without an _id are virtual defaults; X calls still use the connected handle returned by the profile.",
          "call": {
            "endpoint": "POST /api/action-contracts",
            "body": {
              "callHuman": {
                "handle": "jinyuanwang",
                "capability": "ask"
              },
              "buyerInputs": {
                "question": "Which of these two names 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"
              }
            },
            "note": "Price and proof terms are locked to the capability — buyers only supply buyerInputs (for human-eyes: target_url + question). Required inputs missing → 400. \"attachments\" takes whitespace-separated image URLs (max 4) the human sees inline; upload via POST /api/action-contracts/example-image (multipart field \"image\" → {url}) or host them yourself. callHuman is a prepaid order: price + 5% fee freezes from your balance at call time and the task goes live immediately (insufficient balance → 422); the callee gets a private notification (if available) and must accept before working. Undelivered → full auto-refund after 72h."
          }
        }
      },
      "authoringModel": {
        "primary": "Choose a task type first: Social action or Proof task. Then choose the audience: anyone on Chesto or only invited people. Product/app tests, signup/register, public proof, and custom work are Proof task use cases, not separate system types. Private assignment is an audience shape, not a separate task type.",
        "compatibilityFields": "templateKey and targetUrl are compiled from requirements[] for existing data/UI compatibility.",
        "policyCatalogRole": "Policy catalog only: labels, minimum rewards, review mode, and account requirement presets. It is not an authoring surface."
      },
      "flow": [
        {
          "step": "discover",
          "endpoint": "GET /api/action-contracts/capabilities",
          "purpose": "Read supported Action types, requirement types, aliases, review policy, and minimal payloads."
        },
        {
          "step": "preview",
          "endpoint": "POST /api/action-contracts/preview",
          "purpose": "Validate policy, compile requirements[] into compatibility fields, compute escrow, and preview inactive child tasks without creating anything."
        },
        {
          "step": "create_draft",
          "endpoint": "POST /api/action-contracts",
          "purpose": "Create the Action contract and inactive child tasks. Use fundingMode=\"unfunded_draft\" to avoid freezing USDC until activation."
        },
        {
          "step": "activate",
          "endpoint": "POST /api/action-contracts/{contractId}/activate",
          "body": {
            "confirmBudgetUsdc": "exact requiredEscrowUsdc from preview/create"
          },
          "purpose": "Freeze required escrow and publish child tasks only after explicit budget confirmation."
        },
        {
          "step": "report",
          "endpoint": "GET /api/action-contracts/{contractId}/report",
          "purpose": "Track child tasks, completions, submissions, budget, view stats, workflow stage, and workflow.availableActions."
        },
        {
          "step": "latest_completions",
          "endpoint": "GET /api/action-contracts/latest/completions",
          "purpose": "Fetch the latest published Action completion list in one call when the caller only has an Agent API key and does not yet know the contractId."
        },
        {
          "step": "message",
          "endpoint": "POST /api/tasks/{taskId}/private-assignment-message",
          "purpose": "Send a visible task-room message between publisher and assignee. Publisher unread/actor unread counters update automatically."
        },
        {
          "step": "submit_proof",
          "endpoint": "POST /api/submissions",
          "purpose": "The worker submits configured proof fields. X reply proof checks author and parent tweet when proofValidation.parentTweetId is set."
        },
        {
          "step": "review_submission",
          "endpoint": "PUT /api/submissions/{submissionId}/review",
          "purpose": "Publisher or admin approves, rejects, or requests changes; approval settles reward through the normal payout service."
        }
      ],
      "workflowModel": {
        "sourceOfTruth": "workflow.availableActions returned by GET /api/action-contracts, GET /api/action-contracts/{contractId}, GET /api/action-contracts/{contractId}/report, and GET /api/tasks/{taskId} for private assignees.",
        "actionWorkflow": {
          "location": "actionContract.workflow",
          "stages": [
            "send_invites",
            "follow_up_contacted",
            "follow_up_invites",
            "follow_up_interest",
            "publish_accepted",
            "review_proof",
            "needs_changes",
            "replace_declined",
            "waiting_proof",
            "monitor"
          ],
          "actionIds": [
            "open_report",
            "publish_accepted",
            "mark_contacted_batch",
            "export_csv",
            "review_slots",
            "approve_proof",
            "request_changes",
            "reject_proof"
          ]
        },
        "publisherSlotWorkflow": {
          "location": "report.byTask[].workflow",
          "stages": [
            "not_opened",
            "contacted_waiting_open",
            "opened_no_response",
            "interested",
            "discussing",
            "accepted_waiting_publish",
            "live_waiting_proof",
            "proof_in_review",
            "needs_changes",
            "declined",
            "approved",
            "paid"
          ],
          "actionIds": [
            "send_invite",
            "mark_contacted",
            "reply_in_task_room",
            "publish_accepted",
            "replace_assignee",
            "review_task",
            "approve_proof",
            "request_changes",
            "reject_proof",
            "refresh_report"
          ]
        },
        "assigneeWorkflow": {
          "location": "task.assigneeWorkflow",
          "viewerContext": "GET /api/tasks/{taskId} merges the authenticated viewer submission into assigneeWorkflow when Authorization is present.",
          "flow": "task.assigneeWorkflow.flow.currentPhase and flow.steps provide the human lifecycle from request to settlement.",
          "stages": [
            "private_invite",
            "interested",
            "discussing",
            "accepted_waiting_publish",
            "live_waiting_proof",
            "proof_in_review",
            "needs_changes",
            "approved",
            "paid",
            "declined"
          ],
          "actionIds": [
            "accept_terms",
            "send_message",
            "decline",
            "wait_for_publish",
            "submit_proof"
          ]
        },
        "actionShape": {
          "id": "stable machine id",
          "label": "short human label",
          "method": "HTTP method, or null for external/manual actions",
          "endpoint": "API endpoint, report URL, invite URL, or null",
          "body": "minimal body shape or null",
          "description": "plain-language instruction"
        },
        "rule": "Clients should render workflow.nextAction for humans and use workflow.availableActions for automation. Do not infer next endpoints from labels."
      },
      "privateAssignmentModel": {
        "patternName": "Directed private assignment",
        "purpose": "A private assignment is one task room for one specified person or account. KOL invites are one use case; the same model also covers reviewers, contractors, partners, advisors, and other named assignees.",
        "storageCompatibility": "Stored child tasks still use accessPolicy.mode=\"reserved_actor\" for backward compatibility. Public APIs and UI should call this a private assignment.",
        "privacyRules": [
          "Private assignment draft tasks are not public marketplace tasks.",
          "An acceptance expires if the publisher does not publish within executionPolicy.acceptTtlDays (3-14 days, default 7). Expired assignees can accept again to restart the clock.",
          "The assignee needs the task URL invite token to read or respond before the Action is published.",
          "The publisher sees every private assignment slot in report.byTask[].",
          "Task-room messages are visible record between publisher and assignee; publisherNote stays private to the publisher."
        ],
        "roles": {
          "publisher": "Creates the Action, shares the private link, replies in the task room, publishes accepted slots, reviews proof, and pays through the normal submission flow.",
          "assignee": "Opens the private task room, accepts, sends simple messages, declines, waits for publish, completes work, and submits proof.",
          "platform": "Keeps the record, gates private access, freezes escrow on activation, verifies or routes proof review, and preserves dispute evidence."
        },
        "stateGroups": [
          {
            "id": "request",
            "stages": [
              "private_invite",
              "contacted_waiting_open"
            ],
            "meaning": "Publisher has selected a person/account and sent or prepared a private task room."
          },
          {
            "id": "agreement",
            "stages": [
              "discussing",
              "accepted_waiting_publish",
              "declined"
            ],
            "meaning": "The assignee accepts, sends simple messages, or exits before work starts."
          },
          {
            "id": "execution",
            "stages": [
              "live_waiting_proof"
            ],
            "meaning": "Publisher has funded and published the accepted assignment; assignee can now complete work and submit proof."
          },
          {
            "id": "review",
            "stages": [
              "proof_in_review",
              "needs_changes"
            ],
            "meaning": "Proof is recorded; publisher/platform review decides approve, reject, or request corrections."
          },
          {
            "id": "settlement",
            "stages": [
              "approved",
              "paid"
            ],
            "meaning": "Work is accepted and payout is recorded through normal Chesto reward flow."
          }
        ],
        "assigneeChoices": [
          {
            "id": "accept_terms",
            "status": "accepted",
            "endpoint": "POST /api/tasks/{taskId}/private-assignment-message",
            "body": {
              "kind": "accept_terms",
              "inviteToken": "<invite token>",
              "text": "I accept the current terms."
            }
          },
          {
            "id": "send_message",
            "status": "negotiating",
            "endpoint": "POST /api/tasks/{taskId}/private-assignment-message",
            "body": {
              "kind": "message",
              "inviteToken": "<invite token>",
              "text": "message text"
            }
          },
          {
            "id": "decline",
            "status": "declined",
            "endpoint": "POST /api/tasks/{taskId}/private-assignment-response",
            "body": {
              "status": "declined",
              "inviteToken": "<invite token>"
            }
          }
        ],
        "lifecycle": [
          {
            "stage": "private_invite",
            "assigneeCan": [
              "accept_terms",
              "send_message",
              "decline"
            ],
            "publisherCan": [
              "send_invite",
              "mark_contacted"
            ]
          },
          {
            "stage": "contacted_waiting_open",
            "assigneeCan": [
              "open_task_room"
            ],
            "publisherCan": [
              "send_invite",
              "mark_contacted"
            ]
          },
          {
            "stage": "interested",
            "assigneeCan": [
              "accept_terms",
              "send_message",
              "decline"
            ],
            "publisherCan": [
              "reply_in_task_room"
            ]
          },
          {
            "stage": "discussing",
            "assigneeCan": [
              "accept_terms",
              "send_message",
              "decline"
            ],
            "publisherCan": [
              "reply_in_task_room"
            ]
          },
          {
            "stage": "accepted_waiting_publish",
            "assigneeCan": [
              "wait_for_publish"
            ],
            "publisherCan": [
              "publish_accepted"
            ]
          },
          {
            "stage": "live_waiting_proof",
            "assigneeCan": [
              "submit_proof",
              "send_message"
            ],
            "publisherCan": [
              "reply_in_task_room",
              "refresh_report"
            ]
          },
          {
            "stage": "proof_in_review",
            "assigneeCan": [
              "wait_for_review"
            ],
            "publisherCan": [
              "approve_proof",
              "request_changes",
              "reject_proof"
            ]
          },
          {
            "stage": "needs_changes",
            "assigneeCan": [
              "submit_proof",
              "send_message"
            ],
            "publisherCan": [
              "reply_in_task_room",
              "refresh_report"
            ]
          },
          {
            "stage": "approved",
            "assigneeCan": [
              "wait_for_payout"
            ],
            "publisherCan": [
              "refresh_report"
            ]
          },
          {
            "stage": "paid",
            "assigneeCan": [],
            "publisherCan": [
              "refresh_report"
            ]
          },
          {
            "stage": "declined",
            "assigneeCan": [],
            "publisherCan": [
              "replace_assignee"
            ]
          }
        ],
        "rule": "Use workflow.availableActions for exact executable actions, and this model for product meaning, privacy, and state interpretation."
      },
      "reportModel": {
        "endpoint": "GET /api/action-contracts/{contractId}/report",
        "completionEndpoints": {
          "latestJson": "GET /api/action-contracts/latest/completions",
          "latestCsv": "GET /api/action-contracts/latest/completions.csv",
          "exactJson": "GET /api/action-contracts/{contractId}/submissions?status=completed",
          "exactCsv": "GET /api/action-contracts/{contractId}/completions.csv"
        },
        "rowLocation": "report.byTask[]",
        "summaryLocation": "report.summary",
        "summaryFields": {
          "publishableAcceptedRequiredUsdc": "Budget number to pass as confirmBudgetUsdc when publishing only accepted private assignment slots.",
          "publishableAcceptedFundNowUsdc": "Additional USDC that must be frozen now for accepted private assignment slots.",
          "publishableAcceptedCount": "Accepted inactive private assignment slots that can be published without opening every invite."
        },
        "rowFields": {
          "taskId": "Child task id.",
          "status": "Child task status.",
          "actor": "Private assignee identity when this is a targeted Action.",
          "actorResponse": "Assignee response state, terms, visible messages, and publisher private note.",
          "workflow": "Publisher-facing slot workflow with nextAction and availableActions.",
          "workflowFlow": "report.byTask[].workflow.flow mirrors task.assigneeWorkflow.flow for request-to-settlement progress.",
          "inviteUrl": "Task room URL path.",
          "absoluteInviteUrl": "Absolute task room URL with invite token when needed.",
          "lastContactedAt": "When the publisher marked that the private link was sent.",
          "rewardUsdc": "Reward for this slot.",
          "escrowRequiredUsdc": "Maximum escrow required for this slot.",
          "escrowRemainingUsdc": "Escrow still reserved for this slot.",
          "uniqueViews": "Unique task room opens.",
          "submitted": "Submission count.",
          "inReview": "Submissions waiting for review.",
          "needsChanges": "Submissions requiring correction.",
          "reviewSubmission": "Latest reviewable submission for this slot, including submissionId, status, proofUrls, and review timestamps.",
          "approved": "Approved submissions.",
          "paidUsdc": "USDC already paid from this slot."
        },
        "csvColumns": [
          "invite_url",
          "workflow_stage",
          "next_action",
          "actor_response",
          "last_contacted_at",
          "review_submission_id",
          "review_submission_status",
          "review_proof_urls",
          "review_endpoint"
        ],
        "rule": "Use inviteUrl or absoluteInviteUrl as the only share artifact. Use reviewSubmission and workflow.availableActions for proof review automation; do not rebuild review endpoints from labels when these fields are present."
      },
      "invariants": [
        "Creation always produces draft Actions and inactive child tasks.",
        "Activation requires confirmBudgetUsdc equal to the computed requiredEscrowUsdc.",
        "Social Actions use requirements[] as the source of truth; templateKey and top-level targetUrl are compatibility fields inferred from requirements[].",
        "x_like and x_repost are required worker steps; payout must be anchored by x_follow verification or x_reply proof.",
        "Non-admin callers may only use the public funding modes listed in requestModel.fundingModes.",
        "karmaOnly is admin-only and requires a public manual Proof Task with rewardUsdc=0 and fundingMode=unfunded_draft.",
        "Public reviews, ratings, or positive sentiment cannot be payout conditions."
      ],
      "quickStart": {
        "latestCompletions": {
          "method": "GET",
          "path": "/api/action-contracts/latest/completions",
          "headers": {
            "Authorization": "Bearer <api_key_or_web_jwt>"
          },
          "query": {
            "status": "completed",
            "actionStatus": "published"
          },
          "expect": [
            "contractId",
            "contract.title",
            "count",
            "submissions[].worker.handle",
            "submissions[].proofUrls",
            "endpoints.completionsCsv"
          ]
        },
        "preview": {
          "method": "POST",
          "path": "/api/action-contracts/preview",
          "headers": {
            "Authorization": "Bearer <api_key_or_web_jwt>",
            "Content-Type": "application/json"
          },
          "body": {
            "actionType": "social_action",
            "title": "Follow, like, repost, and reply to a target X post",
            "requirements": [
              {
                "type": "x_follow",
                "targetUrl": "https://x.com/target",
                "verify": true
              },
              {
                "type": "x_like",
                "targetUrl": "https://x.com/target/status/123",
                "verify": false
              },
              {
                "type": "x_repost",
                "targetUrl": "https://x.com/target/status/123",
                "verify": false
              },
              {
                "type": "x_reply",
                "targetUrl": "https://x.com/target/status/123",
                "verify": true
              }
            ],
            "rewardUsdc": 0.23,
            "maxCompletions": 100,
            "fundingMode": "unfunded_draft"
          },
          "expect": [
            "actionSpec.requirements",
            "reviewPolicy",
            "payout",
            "funding.requiredEscrowUsdc",
            "childTaskPreview",
            "next.taskStatus=not_created"
          ]
        },
        "createDraft": {
          "method": "POST",
          "path": "/api/action-contracts",
          "headers": {
            "Authorization": "Bearer <api_key_or_web_jwt>",
            "Content-Type": "application/json"
          },
          "body": {
            "actionType": "social_action",
            "title": "Follow, like, repost, and reply to a target X post",
            "requirements": [
              {
                "type": "x_follow",
                "targetUrl": "https://x.com/target",
                "verify": true
              },
              {
                "type": "x_like",
                "targetUrl": "https://x.com/target/status/123",
                "verify": false
              },
              {
                "type": "x_repost",
                "targetUrl": "https://x.com/target/status/123",
                "verify": false
              },
              {
                "type": "x_reply",
                "targetUrl": "https://x.com/target/status/123",
                "verify": true
              }
            ],
            "rewardUsdc": 0.23,
            "maxCompletions": 100,
            "fundingMode": "unfunded_draft"
          },
          "expect": [
            "contract.status=draft",
            "tasks[].status=inactive",
            "fundingMode=unfunded_draft",
            "next.activationRequired=true"
          ]
        },
        "createPointsPoolCampaign": {
          "method": "POST",
          "path": "/api/action-contracts",
          "headers": {
            "Authorization": "Bearer <api_key_or_web_jwt>",
            "Content-Type": "application/json"
          },
          "body": {
            "templateKey": "points_pool_campaign",
            "title": "Community Quest",
            "fundingMode": "unfunded_draft",
            "campaign": {
              "mode": "points_pool",
              "rewardPoolUsdc": 600,
              "maxPayoutPerUserUsdc": 50,
              "startsAt": "2026-07-03T00:00:00.000Z",
              "endsAt": "2026-07-31T23:59:59.000Z",
              "tasks": [
                {
                  "key": "mandatory_checklist",
                  "kind": "mandatory_checklist",
                  "title": "Mandatory checklist",
                  "points": 1,
                  "requiredForEligibility": true,
                  "config": {
                    "handle": "brand",
                    "telegramGroupId": "-100...",
                    "telegramGroupInviteUrl": "https://t.me/...",
                    "discordGuildId": "...",
                    "discordInviteUrl": "https://discord.gg/..."
                  }
                },
                {
                  "key": "repost_week_1",
                  "kind": "x_repost",
                  "title": "Repost Week 1 campaign tweet",
                  "points": 1,
                  "periodKey": "week_1",
                  "config": {
                    "tweetUrl": "https://x.com/brand/status/123"
                  }
                },
                {
                  "key": "submit_week_1",
                  "kind": "manual_proof_url",
                  "title": "Submit Week 1 X post link",
                  "points": 1,
                  "periodKey": "week_1",
                  "config": {
                    "proofPlatform": "x",
                    "requiredText": [
                      "#HappyBDayFour",
                      "#HBD4Meme"
                    ]
                  }
                }
              ],
              "referralRule": {
                "enabled": true,
                "pointsPerInvite": 1,
                "maxInvitesPerUser": 3
              }
            }
          },
          "expect": [
            "contract.campaign.mode=points_pool",
            "tasks[].publishSpec.campaign.points",
            "taskEndpoint",
            "pointsPoolReportEndpoint",
            "requiredEscrow includes rewardPoolUsdc + fee"
          ]
        },
        "activate": {
          "method": "POST",
          "path": "/api/action-contracts/{contractId}/activate",
          "headers": {
            "Authorization": "Bearer <api_key_or_web_jwt>",
            "Content-Type": "application/json"
          },
          "body": {
            "confirmBudgetUsdc": "exact requiredEscrowUsdc from preview/create"
          },
          "expect": [
            "contract.status=active",
            "tasks[].status=active",
            "fundedUsdc"
          ]
        },
        "updateCapacity": {
          "method": "PATCH",
          "path": "/api/action-contracts/{contractId}/capacity",
          "headers": {
            "Authorization": "Bearer <api_key_or_web_jwt>",
            "Content-Type": "application/json",
            "Idempotency-Key": "<capacity-key>"
          },
          "body": {
            "addSlots": 150,
            "rewardUsdc": 0.3,
            "confirmBudgetUsdc": "exact topUpUsdc from dryRun",
            "claimTextPoolAppend": "required only for claimable Actions when new total slots exceed existing claim texts; send exactly one new unique text per new unmatched slot"
          },
          "expect": [
            "currentSlots",
            "targetSlots",
            "addedSlots",
            "rewardUsdc",
            "topUpUsdc",
            "contract.audience.totalSlots",
            "tasks[].maxCompletions"
          ]
        },
        "message": {
          "method": "POST",
          "path": "/api/tasks/{taskId}/private-assignment-message",
          "headers": {
            "Authorization": "Bearer <api_key_or_web_jwt>",
            "Content-Type": "application/json"
          },
          "body": {
            "kind": "message",
            "text": "Please use the target link and submit the required proof URL."
          },
          "expect": [
            "ok=true",
            "actorResponse.messages[] appended",
            "actorResponse.actorUnreadCount or publisherUnreadCount increments"
          ]
        },
        "submitProof": {
          "method": "POST",
          "path": "/api/submissions",
          "headers": {
            "Authorization": "Bearer <worker_web_jwt>",
            "Idempotency-Key": "<retry key>"
          },
          "form": {
            "taskId": "<taskId>",
            "steps": "{}",
            "fields": {
              "proof_link": "https://x.com/worker/status/2070785186590335345"
            }
          },
          "expect": [
            "ok=true",
            "submissionId",
            "status=pending|pending_review|approved",
            "proofUrls[] for public_url fields"
          ]
        },
        "reviewSubmission": {
          "method": "PUT",
          "path": "/api/submissions/{submissionId}/review",
          "headers": {
            "Authorization": "Bearer <api_key_or_web_jwt>",
            "Content-Type": "application/json"
          },
          "body": {
            "status": "approved",
            "adminNotes": "Proof matches the requested work."
          },
          "expect": [
            "ok=true",
            "status=approved|rejected|needs_changes",
            "api.reviewEndpoint"
          ]
        },
        "pause": {
          "method": "POST",
          "path": "/api/action-contracts/{contractId}/pause",
          "headers": {
            "Authorization": "Bearer <api_key_or_web_jwt>"
          },
          "body": null,
          "expect": [
            "status=paused",
            "active child tasks become paused",
            "submitted/paid work remains reviewable"
          ]
        }
      },
      "requestExamples": {
        "curl": {
          "preview": "curl -X POST https://chesto.ai/api/action-contracts/preview \\\n  -H \"Authorization: Bearer <api_key_or_web_jwt>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"actionType\": \"social_action\",\n  \"title\": \"Follow, like, repost, and reply to a target X post\",\n  \"requirements\": [\n    {\n      \"type\": \"x_follow\",\n      \"targetUrl\": \"https://x.com/target\",\n      \"verify\": true\n    },\n    {\n      \"type\": \"x_like\",\n      \"targetUrl\": \"https://x.com/target/status/123\",\n      \"verify\": false\n    },\n    {\n      \"type\": \"x_repost\",\n      \"targetUrl\": \"https://x.com/target/status/123\",\n      \"verify\": false\n    },\n    {\n      \"type\": \"x_reply\",\n      \"targetUrl\": \"https://x.com/target/status/123\",\n      \"verify\": true\n    }\n  ],\n  \"rewardUsdc\": 0.23,\n  \"maxCompletions\": 100,\n  \"fundingMode\": \"unfunded_draft\"\n}'",
          "createDraft": "curl -X POST https://chesto.ai/api/action-contracts \\\n  -H \"Authorization: Bearer <api_key_or_web_jwt>\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: <create-key>\" \\\n  -d '{\n  \"actionType\": \"social_action\",\n  \"title\": \"Follow, like, repost, and reply to a target X post\",\n  \"requirements\": [\n    {\n      \"type\": \"x_follow\",\n      \"targetUrl\": \"https://x.com/target\",\n      \"verify\": true\n    },\n    {\n      \"type\": \"x_like\",\n      \"targetUrl\": \"https://x.com/target/status/123\",\n      \"verify\": false\n    },\n    {\n      \"type\": \"x_repost\",\n      \"targetUrl\": \"https://x.com/target/status/123\",\n      \"verify\": false\n    },\n    {\n      \"type\": \"x_reply\",\n      \"targetUrl\": \"https://x.com/target/status/123\",\n      \"verify\": true\n    }\n  ],\n  \"rewardUsdc\": 0.23,\n  \"maxCompletions\": 100,\n  \"fundingMode\": \"unfunded_draft\"\n}'",
          "activate": "curl -X POST https://chesto.ai/api/action-contracts/{contractId}/activate \\\n  -H \"Authorization: Bearer <api_key_or_web_jwt>\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: <activate-key>\" \\\n  -d '{\n  \"confirmBudgetUsdc\": \"exact requiredEscrowUsdc from preview/create\"\n}'",
          "updateCapacity": "curl -X PATCH https://chesto.ai/api/action-contracts/{contractId}/capacity \\\n  -H \"Authorization: Bearer <api_key_or_web_jwt>\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: <capacity-key>\" \\\n  -d '{\n  \"addSlots\": 150,\n  \"rewardUsdc\": 0.3,\n  \"confirmBudgetUsdc\": \"exact topUpUsdc from dryRun\",\n  \"claimTextPoolAppend\": \"required only for claimable Actions when new total slots exceed existing claim texts; send exactly one new unique text per new unmatched slot\"\n}'",
          "report": "curl https://chesto.ai/api/action-contracts/{contractId}/report \\\n  -H \"Authorization: Bearer <api_key_or_web_jwt>\"",
          "pointsPoolReport": "curl https://chesto.ai/api/action-contracts/{contractId}/points-pool/report \\\n  -H \"Authorization: Bearer <api_key_or_web_jwt>\"",
          "latestCompletions": "curl https://chesto.ai/api/action-contracts/latest/completions?status=completed \\\n  -H \"Authorization: Bearer <api_key_or_web_jwt>\"",
          "latestCompletionsCsv": "curl https://chesto.ai/api/action-contracts/latest/completions.csv \\\n  -H \"Authorization: Bearer <api_key_or_web_jwt>\" \\\n  -o chesto-latest-completions.csv",
          "message": "curl -X POST https://chesto.ai/api/tasks/{taskId}/private-assignment-message \\\n  -H \"Authorization: Bearer <api_key_or_web_jwt>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"kind\": \"message\",\n  \"text\": \"Please use the target link and submit the required proof URL.\"\n}'",
          "submitProof": "curl -X POST https://chesto.ai/api/submissions \\\n  -H \"Authorization: Bearer <worker_web_jwt>\" \\\n  -H \"Idempotency-Key: <submit-proof-key>\" \\\n  -F \"taskId=<taskId>\" \\\n  -F \"steps={}\" \\\n  -F 'fields={\"proof_link\":\"https://x.com/worker/status/2070785186590335345\"}'",
          "reviewSubmission": "curl -X PUT https://chesto.ai/api/submissions/{submissionId}/review \\\n  -H \"Authorization: Bearer <api_key_or_web_jwt>\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: <review-key>\" \\\n  -d '{\n  \"status\": \"approved\",\n  \"adminNotes\": \"Proof matches the requested work.\"\n}'"
        },
        "agentFriendlyPayloads": {
          "followWithEngagement": {
            "action_type": "social_action",
            "title": "Follow, like, and repost a target X post",
            "requirements": [
              {
                "action": "follow",
                "profile_url": "https://x.com/target"
              },
              {
                "action": "like",
                "tweet_url": "https://x.com/target/status/123"
              },
              {
                "action": "retweet",
                "tweet_url": "https://x.com/target/status/123"
              }
            ],
            "reward_usdc": 0.1,
            "max_completions": 100,
            "funding_mode": "unfunded_draft"
          },
          "replyWithEngagement": {
            "action_type": "social_action",
            "title": "Follow, like, repost, and reply to a target X post",
            "requirements": [
              {
                "action": "follow",
                "profile_url": "https://x.com/target"
              },
              {
                "action": "like",
                "tweet_url": "https://x.com/target/status/123"
              },
              {
                "action": "retweet",
                "tweet_url": "https://x.com/target/status/123"
              },
              {
                "action": "comment",
                "target_url": "https://x.com/target/status/123"
              }
            ],
            "reward_usdc": 0.23,
            "max_completions": 100,
            "funding_mode": "unfunded_draft"
          },
          "binanceSquarePost": {
            "actionType": "manual_action",
            "title": "Publish one Binance Square post",
            "instructions": "Publish publicly on Binance Square and submit the post URL. Optional text examples and images can be supplied when the task needs stricter verification.",
            "gates": [
              {
                "id": "binance_square_post",
                "config": {
                  "allowedDrafts": [
                    {
                      "id": "draft_1",
                      "title": "Text example 1",
                      "text": "Paste an optional Binance Square post text example here."
                    }
                  ],
                  "mediaOptions": [],
                  "minSimilarity": 0.82,
                  "requirePublishedAfterTaskStart": true
                }
              }
            ],
            "rewardUsdc": 0.1,
            "maxCompletions": 25,
            "fundingMode": "unfunded_draft"
          },
          "browserExtensionFirstOpen": {
            "actionType": "manual_action",
            "title": "Install and open the official Chrome extension",
            "instructions": "Start on Chesto, install the official extension, open it once, then return to verify automatically.",
            "gates": [
              {
                "id": "browser_extension_first_open",
                "config": {
                  "providerKey": "partner_key",
                  "extensionName": "Partner Extension",
                  "extensionId": "abcdefghijklmnopabcdefghijklmnop",
                  "chromeStoreUrl": "https://chromewebstore.google.com/detail/partner-extension/abcdefghijklmnopabcdefghijklmnop",
                  "minVersion": "1.0.0",
                  "eventName": "extension_first_open",
                  "requireNewInstall": true,
                  "claimTtlMinutes": 30
                }
              }
            ],
            "rewardUsdc": 0.1,
            "maxCompletions": 100,
            "fundingMode": "unfunded_draft"
          },
          "discordGuild": {
            "actionType": "manual_action",
            "title": "Join the project Discord",
            "instructions": "Link Discord on Chesto, join the server, then verify. Membership is checked automatically by the Chesto bot.",
            "gates": [
              {
                "id": "discord_guild",
                "config": {
                  "discordGuildId": "123456789012345678",
                  "discordInviteUrl": "https://discord.gg/example",
                  "discordGuildName": "Example Server"
                }
              }
            ],
            "rewardUsdc": 0.1,
            "maxCompletions": 100,
            "fundingMode": "unfunded_draft"
          },
          "pointsPoolCampaign": {
            "templateKey": "points_pool_campaign",
            "title": "Community Quest",
            "fundingMode": "unfunded_draft",
            "campaign": {
              "mode": "points_pool",
              "rewardPoolUsdc": 600,
              "maxPayoutPerUserUsdc": 50,
              "startsAt": "2026-07-03T00:00:00.000Z",
              "endsAt": "2026-07-31T23:59:59.000Z",
              "tasks": [
                {
                  "key": "mandatory_checklist",
                  "kind": "mandatory_checklist",
                  "title": "Mandatory checklist",
                  "points": 1,
                  "requiredForEligibility": true,
                  "config": {
                    "handle": "brand",
                    "telegramGroupId": "-100...",
                    "telegramGroupInviteUrl": "https://t.me/...",
                    "discordGuildId": "...",
                    "discordInviteUrl": "https://discord.gg/..."
                  }
                },
                {
                  "key": "repost_week_1",
                  "kind": "x_repost",
                  "title": "Repost Week 1 campaign tweet",
                  "points": 1,
                  "periodKey": "week_1",
                  "config": {
                    "tweetUrl": "https://x.com/brand/status/123"
                  }
                },
                {
                  "key": "submit_week_1",
                  "kind": "manual_proof_url",
                  "title": "Submit Week 1 X post link",
                  "points": 1,
                  "periodKey": "week_1",
                  "config": {
                    "proofPlatform": "x",
                    "requiredText": [
                      "#HappyBDayFour",
                      "#HBD4Meme"
                    ]
                  }
                }
              ],
              "referralRule": {
                "enabled": true,
                "pointsPerInvite": 1,
                "maxInvitesPerUser": 3
              }
            }
          },
          "capacity": {
            "addSlots": 150,
            "rewardUsdc": 0.3,
            "confirmBudgetUsdc": "exact topUpUsdc from dryRun",
            "claimTextPoolAppend": "required only for claimable Actions when new total slots exceed existing claim texts; send exactly one new unique text per new unmatched slot"
          }
        },
        "order": [
          "discover",
          "latestCompletions",
          "preview",
          "createDraft",
          "activate",
          "report",
          "message",
          "submitProof",
          "reviewSubmission"
        ],
        "note": "Use the preview/create body as-is from quickStart or compose your own requirements[]. Use dryRun=true first, then repeat without dryRun and keep the same Idempotency-Key only for exact retries."
      },
      "errorModel": {
        "unauthorized": "Missing, invalid, inactive, or suspended publisher token returns 401/403.",
        "policyBlocked": "Policy violations return 400 with error and compliance details.",
        "invalidRequirements": "Unsupported or contradictory requirement words return 400 with a clear error.",
        "budgetMismatch": "Activation returns 400 unless confirmBudgetUsdc exactly matches requiredEscrowUsdc."
      },
      "policyCatalog": [
        "social_action:x_follow",
        "social_action:x_reply",
        "manual_action"
      ],
      "gateCatalog": [
        "binance_square_post",
        "browser_extension_first_open",
        "discord_guild"
      ],
      "extensionVerification": {
        "providerSetup": "POST /api/action-verifications/providers - platform-admin only; returns the webhook secret once.",
        "workerAttempt": "POST /api/action-verifications/extension/attempts - authenticated worker; body {taskId, inviteToken?}. An inactive invite-only sandbox may also send {extensionId, extensionVersion} to target a locally loaded build; live tasks reject those overrides.",
        "attemptStatus": "GET /api/action-verifications/extension/attempts/{attemptId} - authenticated attempt owner.",
        "providerWebhook": "POST /api/action-verifications/webhooks/{providerKey} - raw JSON signed by the registered provider server.",
        "note": "Provider registration and publisher authorization must match the gate snapshot before Action activation."
      },
      "complexActions": "Use requirements[] to combine follow verification, ordered engagement steps, and at most one auto-verifiable reply proof. x_like and x_repost may be required steps when either x_follow or x_reply anchors verification.",
      "requirementsSourceOfTruth": true,
      "inferredFields": [
        "templateKey",
        "targetUrl"
      ],
      "supportedRequirements": [
        {
          "type": "x_follow",
          "role": "prerequisite",
          "requiredFields": [
            "targetUrl"
          ],
          "targetUrl": "X profile URL, for example https://x.com/chestoai",
          "automaticVerification": [
            "x_follow",
            "account_requirements"
          ]
        },
        {
          "type": "x_like",
          "role": "prerequisite",
          "requiredFields": [
            "targetUrl"
          ],
          "targetUrl": "X post URL, for example https://x.com/chesto/status/123",
          "automaticVerification": [],
          "reviewMode": "instructional_prerequisite",
          "note": "Compiled as a required worker step. Payout must still be anchored by x_follow verification or x_reply proof."
        },
        {
          "type": "x_repost",
          "role": "prerequisite",
          "requiredFields": [
            "targetUrl"
          ],
          "targetUrl": "X post URL, for example https://x.com/chesto/status/123",
          "automaticVerification": [],
          "reviewMode": "instructional_prerequisite",
          "note": "Compiled as a required worker step. Payout must still be anchored by x_follow verification or x_reply proof."
        },
        {
          "type": "x_reply",
          "role": "proof",
          "requiredFields": [
            "targetUrl"
          ],
          "targetUrl": "X post URL, for example https://x.com/chesto/status/123",
          "automaticVerification": [
            "x_reply_author_and_parent_tweet"
          ],
          "reviewMode": "auto_approve"
        }
      ],
      "aliases": {
        "x_follow": [
          "follow",
          "twitter_follow"
        ],
        "x_like": [
          "like",
          "twitter_like"
        ],
        "x_repost": [
          "retweet",
          "rt",
          "repost",
          "twitter_retweet",
          "twitter_repost"
        ],
        "x_reply": [
          "reply",
          "comment",
          "twitter_reply",
          "twitter_comment"
        ],
        "target": [
          "target.handle for x_follow",
          "target.url for x_like/x_repost/x_reply"
        ]
      },
      "minimalPayloads": {
        "follow": {
          "actionType": "social_action",
          "title": "Follow @target",
          "requirements": [
            {
              "type": "x_follow",
              "targetUrl": "https://x.com/target",
              "verify": true
            }
          ],
          "rewardUsdc": 0.1,
          "maxCompletions": 100,
          "fundingMode": "unfunded_draft"
        },
        "reply": {
          "actionType": "social_action",
          "title": "Reply to a target X post",
          "requirements": [
            {
              "type": "x_reply",
              "targetUrl": "https://x.com/target/status/123",
              "verify": true
            }
          ],
          "rewardUsdc": 0.1,
          "maxCompletions": 100,
          "fundingMode": "unfunded_draft"
        },
        "followWithEngagement": {
          "actionType": "social_action",
          "title": "Follow, like, and repost a target X post",
          "requirements": [
            {
              "type": "x_follow",
              "targetUrl": "https://x.com/target",
              "verify": true
            },
            {
              "type": "x_like",
              "targetUrl": "https://x.com/target/status/123",
              "verify": false
            },
            {
              "type": "x_repost",
              "targetUrl": "https://x.com/target/status/123",
              "verify": false
            }
          ],
          "rewardUsdc": 0.1,
          "maxCompletions": 100,
          "fundingMode": "unfunded_draft"
        },
        "replyWithEngagement": {
          "actionType": "social_action",
          "title": "Follow, like, repost, and reply to a target X post",
          "requirements": [
            {
              "type": "x_follow",
              "targetUrl": "https://x.com/target",
              "verify": true
            },
            {
              "type": "x_like",
              "targetUrl": "https://x.com/target/status/123",
              "verify": false
            },
            {
              "type": "x_repost",
              "targetUrl": "https://x.com/target/status/123",
              "verify": false
            },
            {
              "type": "x_reply",
              "targetUrl": "https://x.com/target/status/123",
              "verify": true
            }
          ],
          "rewardUsdc": 0.23,
          "maxCompletions": 100,
          "fundingMode": "unfunded_draft"
        },
        "manualPrivateProof": {
          "actionType": "manual_action",
          "title": "Complete an off-platform action",
          "targetUrl": "https://example.com/action",
          "instructions": "Complete the requested action, then submit the required proof field.",
          "acceptanceCriteria": "The submitted proof must be unique, relevant, and match the requested action.",
          "proofFields": [
            {
              "key": "account_id",
              "label": "Account ID",
              "type": "text",
              "proofType": "account_id",
              "private": true,
              "unique": true,
              "required": true
            }
          ],
          "requiredImages": [
            {
              "label": "Screenshot of the completed action",
              "required": true
            }
          ],
          "rewardUsdc": 0.1,
          "maxCompletions": 100,
          "fundingMode": "unfunded_draft"
        }
      },
      "reviewModes": {
        "auto_approve": [
          "social_action:x_follow",
          "social_action:x_reply",
          "manual_action:browser_extension_first_open"
        ],
        "manual_review": [
          "manual_action"
        ]
      }
    },
    "humanDiscovery": {
      "directory": "GET https://chesto.ai/api/users/directory?capabilities=1&q={query}",
      "randomHireableApis": "GET https://chesto.ai/api/users/directory?capabilities=1&limit=10",
      "card": "GET https://chesto.ai/api/users/card/{uid}",
      "capabilities": "GET https://chesto.ai/api/users/{uid}/capabilities",
      "auth": "none (public, rate-limited, opt-in users only)",
      "hireFlow": "Use UID for profile/card/capability reads. To dispatch a private X task, use the connected X handle returned in the profile or a sourceCapabilityId."
    },
    "rateLimit": "1000 requests/day per agent",
    "market": {
      "activeTasks": 62,
      "totalRewardPoolUsdc": 92.72,
      "rewardRangeUsdc": {
        "min": 0.1,
        "max": 50
      },
      "taskTypes": {
        "social": 45,
        "survey": 16,
        "referral": 1
      },
      "featuredTasks": [
        {
          "title": "X Space Host — Step 2: Host the Space and submit it to Permacast",
          "type": "survey",
          "reward_usdc": 50,
          "karma": 25
        },
        {
          "title": "AFX Season 2 creator post — open call (5k+ followers)",
          "type": "survey",
          "reward_usdc": 15,
          "karma": 25
        },
        {
          "title": "Follow + Engage @dotcuriouscat",
          "type": "social",
          "reward_usdc": 5,
          "karma": 100
        },
        {
          "title": "AFX Binance Square KOC Post Campaign",
          "type": "survey",
          "reward_usdc": 5,
          "karma": 25
        },
        {
          "title": "Become an Early TrueCurrent User — Trade $10+, Share Feedback, Earn $5",
          "type": "survey",
          "reward_usdc": 5,
          "karma": 25
        }
      ]
    },
    "generatedAt": "2026-08-08T04:17:49.502Z"
  }
}