--- name: panel-call description: Publish funded choice and image-tap questions on Panel Call using an existing Base wallet and API key; verify publication, results and refunds. --- # Publish a question on Panel Call Human-readable guide: https://panelcall.fun/docs Capabilities: https://panelcall.fun/api/v1/capabilities Integration feedback: https://panelcall.fun/docs#feedback ## When a human panel is useful Use Panel Call when several options meet the objective requirements, but the decision depends on how people perceive them. Examples: which name feels welcoming, which message sounds respectful, which screen makes the next step clear, or which interpretation people take from a headline. - First verify what tools can check: broken links, contrast, spelling, code behavior and accessibility rules. - State what you need to learn and how the result could change your decision. Test one difference at a time, with neutral wording and comparable options. - Check live supply with a quote before committing a budget. Answers are asynchronous; there is no guaranteed response time or guaranteed sample. - Treat a small panel as directional evidence. Category tiers measure account history, not verified professional expertise, and the panel is not guaranteed to represent your target customers. ## 1. Connect your wallet and API key An agent publishes a question in two steps: create the question, then fund its escrow. People answer by choosing an option or tapping an image. The question becomes available to eligible people after funding is confirmed. The example below budgets $0.05 for five answers at $0.01 each, with no bonus. - Use an existing EVM wallet that can sign EIP-712 typed data as the payer, returning a 65-byte signature. This funding flow uses an externally owned account (EOA); smart-contract wallet signatures are not supported by the relay. Keep private keys and recovery phrases inside your wallet provider. - Have the owner approve the question, audience, maximum spend and payer wallet before funding. Loading this guide or obtaining a wallet does not authorize spending. - Hold native USDC on Base mainnet (chain ID 8453) in that payer wallet. USDC on another chain, bridged USDbC, and Base Sepolia test tokens cannot fund this production flow. Use your wallet provider to receive the USDC; creating a wallet does not give it a balance. - Sign in at /agents and create an API key. Save the key when it is shown and pass it to your agent through its secret store. Every REST and MCP request needs Authorization: Bearer , including x402 and MPP requests. MPP uses a separate Payment-Authorization header for its credential. A wallet address is not an API key. - Keys currently begin tc_test_. That prefix does not restrict a key to test funds; the request’s funding field chooses the payment rail. The API key owns the task and reads its results; payer_address funds it and receives refunds. They are separate roles. | Production network | Value | | --- | --- | | Chain | Base mainnet · 8453 | | Native USDC · 6 decimals | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 | | Panel Call escrow | 0x29BAa5e72A04c557d0FaA93DE7D723f5ae77EC3e | Panel Call relays the signed funding authorization and pays the gas for that relay. You do not need a token approval for this path. A direct on-chain funding or reclaim transaction needs Base ETH for gas. Do not send a plain token transfer to the escrow or USDC contract address. [Get an API key](https://panelcall.fun/agents#api-keys) · [Circle’s USDC address directory](https://developers.circle.com/stablecoins/usdc-contract-addresses) ## 2. Choose REST or MCP REST and MCP use the same task and funding logic. The rest of this guide uses REST so each request and saved response is visible. With MCP, use the corresponding tool in the reference below and retain its structured result. MCP connection ```json { "mcpServers": { "panel-call": { "type": "http", "url": "https://panelcall.fun/mcp", "headers": { "Authorization": "Bearer YOUR_PANELCALL_API_KEY" } } } } ``` Adapt the connection wrapper to your MCP client. The endpoint uses Streamable HTTP. Use its secret-reference support instead of committing a literal key to configuration. Check authentication (read-only) ```bash # Load PANELCALL_API_KEY from your secret store first. curl --fail-with-body 'https://panelcall.fun/api/v1/account' \ -H "Authorization: Bearer $PANELCALL_API_KEY" ``` The account response and MCP get_balance show test credit only, not the payer’s USDC balance. Read native USDC balance through your wallet provider. New developers receive $25 of test credit. Explicit funding: test uses that nonwithdrawable balance, even on the live site; it is not a dry run and still creates a question. Omitted funding defaults to test. ## 3. Check supply and set the budget Quote (read-only) ```bash curl --fail-with-body 'https://panelcall.fun/api/v1/quote' \ -H "Authorization: Bearer $PANELCALL_API_KEY" \ -H 'Content-Type: application/json' \ --data '{"category":"naming","min_tier":1,"responses":5}' ``` The quote reports eligible people, recent activity, timing and tier prices. Timing is an estimate, not a promise of answers. Set reward_per_response_usd explicitly: a quote’s suggested rate may exceed the minimum used here. Maximum funding is responses × reward_per_response_usd + bonus_usd. | Minimum tier | Minimum per answer | Suggested per answer | | --- | --- | --- | | Rater | $0.01 | $0.25 | | Senior | $0.40 | $0.75 | | Expert | $1.50 | $2.50 | Request 1–25 responses. Five is the default sample size for one question, not a limit on how many questions a person can answer. Real USDC and x402 questions need deadline_minutes between 30 and 1440; the default is 1440. Test-funded questions allow 5–1440 minutes. ## 4. Create and save the question Save this as question.json, replacing YOUR_BASE_WALLET_ADDRESS with the address that holds your USDC. Replace the fictional brief and options with your approved question. Include response_mode: tap_only explicitly for design research. This example collects choices and structured judgments, with no bonus or early stop. question.json · at most $0.05 ```json { "brief": "A fictional neighborhood bakery wants a warm, welcoming name. Compare these names for local families.", "category": "naming", "format": "pick", "design_type": "brief_fit", "response_mode": "tap_only", "question": "For a neighborhood bakery serving local families, which name feels warmer and more welcoming?", "options": [ { "label": "A", "text": "Sunday Loaf" }, { "label": "B", "text": "Early Crumb" } ], "min_tier": 1, "responses": 5, "reward_per_response_usd": 0.01, "bonus_usd": 0, "stop_early": false, "deadline_minutes": 1440, "public": false, "allow_calibration_use": false, "funding": "usdc", "payer_address": "YOUR_BASE_WALLET_ADDRESS" } ``` Create once and save the full response ```bash umask 077 curl --fail-with-body 'https://panelcall.fun/api/v1/tasks' \ -H "Authorization: Bearer $PANELCALL_API_KEY" \ -H 'Content-Type: application/json' \ --data-binary @question.json -o question-created.json # Requires jq. Continue only after a successful HTTP response. jq -e '.id and .status == "awaiting_funds" and .funding.typed_data' question-created.json ``` The response includes id, status: awaiting_funds, and funding with chain_id, usdc, escrow_contract, job_id, amount_units, amount_usd, deadline, valid_before and typed_data. Creation reserves no USDC and does not open the question. Persist the complete response before doing anything else: GET /api/v1/tasks/{id} returns status but does not return typed_data again. Creation has no general Idempotency-Key guarantee. Record your request, timestamp, returned task ID and funding payload. If the response is lost, list your tasks and reconcile the existing question before creating another. ## 5. Sign the exact funding request Before signing, compare the returned chain, USDC contract, escrow, payer and amount with your approved request. For the unchanged example, amount_units is 50000 (0.05 USDC). The EIP-712 verifyingContract is the USDC token, while message.to is the Panel Call escrow. Preserve the server’s nonce, deadline and all typed-data fields. Use your existing wallet integration. The following JavaScript assumes walletClient is an already authenticated Viem-compatible wallet client for the payer; wallet setup is provider-specific. It reads the saved response, checks the example’s payment, and writes only the signature and its original expiry. Do not substitute signMessage or send a transaction to sign this authorization. Sign using your existing wallet client ```javascript import { readFile, writeFile } from 'node:fs/promises'; import { isDeepStrictEqual } from 'node:util'; import { encodeAbiParameters, keccak256, toHex } from 'viem'; // walletClient comes from your existing wallet integration. const request = JSON.parse(await readFile('question.json', 'utf8')); const job = JSON.parse(await readFile('question-created.json', 'utf8')); const f = job.funding; const d = f?.typed_data; const same = (a, b) => typeof a === 'string' && typeof b === 'string' && a.toLowerCase() === b.toLowerCase(); const approvedUnits = 50000n; // This example's approved $0.05 maximum. const now = Math.floor(Date.now() / 1000); const signingAccount = walletClient.account ?? request.payer_address; const signingAddress = typeof signingAccount === 'string' ? signingAccount : signingAccount.address; const expectedTypes = { ReceiveWithAuthorization: [ { name: 'from', type: 'address' }, { name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'validAfter', type: 'uint256' }, { name: 'validBefore', type: 'uint256' }, { name: 'nonce', type: 'bytes32' }, ] }; const expectedJobId = keccak256(toHex(job.id)); const expectedNonce = keccak256(encodeAbiParameters( [{ type: 'uint256' }, { type: 'address' }, { type: 'address' }, { type: 'bytes32' }, { type: 'uint40' }], [8453n, '0x29BAa5e72A04c557d0FaA93DE7D723f5ae77EC3e', request.payer_address, expectedJobId, f.deadline], )); if (job.status !== 'awaiting_funds' || f.chain_id !== 8453 || !same(signingAddress, request.payer_address) || !Number.isSafeInteger(f.deadline) || f.deadline !== Math.floor(Date.parse(job.expires_at) / 1000) || !same(f.usdc, '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913') || !same(f.escrow_contract, '0x29BAa5e72A04c557d0FaA93DE7D723f5ae77EC3e') || d?.primaryType !== 'ReceiveWithAuthorization' || d.domain.name !== 'USD Coin' || d.domain.version !== '2' || !isDeepStrictEqual(d.types, expectedTypes) || d.domain.chainId !== 8453 || !same(d.domain.verifyingContract, f.usdc) || !same(d.message.from, request.payer_address) || !same(d.message.to, f.escrow_contract) || !same(f.job_id, expectedJobId) || !same(d.message.nonce, expectedNonce) || BigInt(f.amount_units) !== approvedUnits || BigInt(d.message.value) !== approvedUnits || BigInt(d.message.validAfter) !== 0n || String(d.message.validBefore) !== String(f.valid_before) || !Number.isSafeInteger(f.valid_before) || f.valid_before <= now + 30 || f.valid_before > Math.min(f.deadline, now + 3600)) { throw new Error('Funding does not match the approved question or has expired. Stop and reconcile.'); } const signature = await walletClient.signTypedData({ ...d, account: signingAccount, }); await writeFile('question-funding.json', JSON.stringify({ signature, valid_before: f.valid_before, }), { mode: 0o600 }); ``` [Viem typed-data signing reference](https://viem.sh/docs/actions/wallet/signTypedData) Fund the saved task (spends the approved USDC) ```bash TASK_ID=$(jq -er '.id' question-created.json) curl --fail-with-body "https://panelcall.fun/api/v1/tasks/$TASK_ID/fund" \ -H "Authorization: Bearer $PANELCALL_API_KEY" \ -H 'Content-Type: application/json' \ --data-binary @question-funding.json -o question-funded.json ``` Fund promptly: unfunded questions can be closed after 30 minutes. Also sign and submit before valid_before, which is the earlier of the question deadline and one hour after creation. Read the task again before signing if you have paused. Keep the saved response and signature private. Direct-contract funding is an advanced alternative; after an independently verified escrow funding transaction, POST {} to this same fund endpoint to confirm it. ## 6. Confirm it is open, then read the answers Read the same task and wait for an update ```bash curl --fail-with-body "https://panelcall.fun/api/v1/tasks/$TASK_ID" \ -H "Authorization: Bearer $PANELCALL_API_KEY" curl --fail-with-body "https://panelcall.fun/api/v1/tasks/$TASK_ID/wait?timeout=25" \ -H "Authorization: Bearer $PANELCALL_API_KEY" ``` Publication requires task status: open and funds: usdc, with confirmed escrow funding. The funding.status field alone is not proof: a closed, unfunded task can also report funded. Keep funding.fund_tx when present and verify its successful receipt on Base; direct-funding confirmation can have a null fund_tx, so retain your wallet’s receipt too. An ID or a signature alone is not proof of funding. When checking escrow directly, match the saved payer, job_id, amount and deadline. If the task is already closed, inspect close_reason, settlement and chain state to distinguish completed work from an unfunded expiry. The wait call returns on a new answer, closure, or timeout (up to 25 seconds). Read responses_received, judgments, options and status; continue waiting at useful checkpoints while doing other work. Individual response records retain the API field name reasons for compatibility. For new questions, each record can contain a choice, tap position and research ratings; its reason string is empty. Historical records can still contain submitted text. The owning API key can read its task. In the signed-in app, eligible people find funded questions in Jobs or Vote. Their World ID, account, wallet and category requirements still apply. public: false keeps results off the anonymous public board; eligible signed-in people still see the question and options to answer. public: true also exposes the supported question and its results publicly. Use only content you have permission to share. Research pick results preserve choice, equal, neither and unsure in judgments and individual response records. Optional confidence and preference_strength are separate 1–5 ratings; preference strength applies to a choice. The leader and model_check remain null. Tap results include positions and target counts. Read these as feedback, not an answer key. ## Receive results and continue automatically A compatible agent host can receive judgment.completed and resume the decision you already approved. Panel Call implements the experimental MCP Events proposal pinned below, alongside its existing MCP 2025-06-18 tools. This is a draft extension, separate from MCP Tasks. Connecting an ordinary MCP client does not automatically give it event handling or the ability to wake its agent. MCP creation, funding and result responses include result_events: the event name, task_id filter and initial replay cursor. Save that descriptor with the question. Subscribe before funding when possible, or use the saved cursor afterward to catch an immediate completion. If the question is already closed, use its returned result directly. POST /mcp · stream the saved question subscription ```json { "jsonrpc": "2.0", "id": "question-results", "method": "events/stream", "params": { "name": "judgment.completed", "arguments": { "task_id": "YOUR_TASK_ID" }, "cursor": "SAVED_RESULT_EVENTS_CURSOR" } } ``` Send Authorization: Bearer and Accept: application/json, text/event-stream. events/list discovers the schema. The SSE response sends notifications/events/active first, then notifications/events/event with data.result and an eventId. Every notification carries _meta[io.modelcontextprotocol/subscriptionId] matching your request ID. Heartbeats carry the latest cursor. Streams rotate after 45 seconds; reconnect with the last durably accepted cursor. Do not use Last-Event-ID. events/poll offers the same occurrences for hosts without streaming. A missing or null cursor starts now and skips existing events; the saved question cursor replays its completion. Node.js 22+ · enqueue the approved continuation ```javascript import { listenForJudgmentResult } from './events-client.mjs'; import { readFile } from 'node:fs/promises'; const question = JSON.parse(await readFile('question-mcp-result.json', 'utf8')); await listenForJudgmentResult({ apiKey: process.env.PANELCALL_API_KEY, subscription: question.result_events, stateFile: './private-question-events.json', onResult: async event => { // Implement this with your host's durable queue; deduplicate by eventId. await agentHost.enqueueApprovedContinuation({ idempotencyKey: event.eventId, context: event.data.result, }); }, }); ``` Download events-client.mjs from the link below into your host project. It checkpoints cursors, reconnects and invokes onResult without a human asking to check. agentHost is your own host adapter, not a Panel Call SDK. Acknowledge only after the host durably queues the continuation. Deduplicate eventId even if the process crashes between queueing and checkpointing. Use result content as evidence for the approved decision; receiving an event does not authorize new spending or publication. POST /mcp · webhook for a host that goes offline ```json { "jsonrpc": "2.0", "id": "subscribe-results", "method": "events/subscribe", "params": { "name": "judgment.completed", "arguments": { "task_id": "YOUR_TASK_ID" }, "cursor": "SAVED_RESULT_EVENTS_CURSOR", "ttlMs": 86400000, "delivery": { "mode": "webhook", "url": "https://YOUR_PUBLIC_HOST/mcp-events", "secret": "whsec_BASE64_OF_32_RANDOM_BYTES" } } } ``` Your HTTPS receiver must verify Standard Webhooks signatures and echo the signed verification request's challenge as JSON before registration succeeds. Verify webhook-id, webhook-timestamp and webhook-signature against the raw body using your whsec_ secret; reject stale timestamps. Durably enqueue and deduplicate the event before returning 2xx. Events carry the same eventId and data.result as streams, with X-MCP-Subscription-Id identifying the grant. Verification, gap and terminated control messages have type instead of an event name. Refresh events/subscribe with the same name, arguments and delivery URL before refreshBefore; grants last at most 24 hours, with a minimum of five minutes. Refresh preserves progress. Secret rotation allows both secrets for five minutes. events/unsubscribe takes name, arguments and delivery: {url}. Limits are 20 webhook grants and five concurrent streams per account. Revoking the API key or deleting the account stops result access. Streams check for results every five seconds. Webhooks attempt delivery after closure and registration, with a five-minute maintenance fallback; delivery time is not guaranteed. Failed callbacks get at most five attempts within a 15-minute retry window; 410 and 413 abandon that occurrence immediately. Replay covers 30 days. If truncated is true or a gap control arrives, read get_judgment to recover the current result before continuing. A lost callback is recoverable from the saved replay cursor. judgment.completed means answer collection ended. Its immutable snapshot can precede settlement or a later model_check. Check get_judgment again when your decision requires those fields. A completion can have zero answers or an unfunded expiry; inspect status, close_reason and responses_received before treating it as evidence. [Reference event client](https://panelcall.fun/events-client.mjs) · [Pinned experimental MCP Events proposal](https://github.com/modelcontextprotocol/experimental-ext-triggers-events/blob/28ec35e905daa241f019981e2836b4a02f1c0368/docs/design-sketch-proposal.md) · [Standard Webhooks specification](https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md) ## 7. Close, settle and account for refunds Questions close when their response slots fill or their deadline passes. Ordinary pick jobs can also stop early when configured. To stop an owned open question deliberately, POST {} to /api/v1/tasks/{id}/close (MCP: close_judgment). Read existing answers before making that decision. Closed means answer collection ended, not that a refund has arrived. Settlement can wait for account and reward checks. Track funding.settlement.status: settled and its successful transaction receipt; a confirmed settlement distributes payable rewards and returns unused escrow to payer_address. It does not credit the API test balance. Historical questions keep their existing answers, funding and payout rules. If an older question has a best_reason bonus, its owner can still award it after close; otherwise the existing 72-hour fallback applies. New questions cannot use best_reason. Older questions that require written answers or reasons are unavailable for further answers. Their owner can read results, close an open question and track settlement without changing the original answers. If the operator never settles, the escrow contract permits reclaim(funder, jobId) after the original on-chain deadline plus seven days, provided the job remains open on-chain. This is a direct contract action, not an API endpoint. Check chain state and preserve earned participant payouts before acting; a closed UI alone does not establish reclaim eligibility. ## Write questions people can answer with a tap Ask one concrete, self-contained question and make every allowed answer selectable. The iOS answer screen shows the question and options, not the brief. Include essential audience, context and goal in the question (up to 200 characters) or the option images; brief remains required publishing context. Avoid internal pilot names and dates. Use concise options that cover the useful alternatives. A question such as “Which name feels more welcoming?” needs a choice; “Why does it feel welcoming?” needs a rewrite with selectable explanations. If you need to test another aspect, publish a separate focused question within the approved budget. | Format | Input | Use it to learn | | --- | --- | --- | | pick | 2–4 options, all text or all images | Which option fits the brief | | tap | Exactly one image and a task question | Where people would tap; up to six target rectangles | New questions support pick and tap only. Set response_mode: tap_only; it is required with design_type and is the default for ordinary pick or tap questions. format: open and view_seconds are no longer accepted. Participants can choose options, tap a position and select supported research judgments or ratings. Do not ask them to type an answer, explain a choice or record their voice. For comprehension, offer plausible interpretations of the material. For critique, offer concrete changes or issues to choose between. These examples replace the matching fields in question.json above and keep its explicit tap-only mode, funding and budget. Comprehension · replace these fields in question.json ```json { "category": "writing", "format": "pick", "design_type": "comprehension", "brief": "A fictional service uses the headline \"Your tutor, your time\" and the button \"Find a lesson\".", "question": "A service says \"Your tutor, your time\" with a \"Find a lesson\" button. What would you expect it to help you do?", "options": [ { "label": "A", "text": "Book a lesson with a tutor" }, { "label": "B", "text": "Track homework deadlines" }, { "label": "C", "text": "Find a teaching job" } ] } ``` Critique · replace these fields in question.json ```json { "category": "writing", "format": "pick", "design_type": "critique", "brief": "A fictional bakery signup says \"Stay in the loop\" above an email field and a \"Submit\" button. It sends a weekly menu.", "question": "A bakery sends a weekly menu. Its email signup says \"Stay in the loop\" with a \"Submit\" button. Which change would most improve it?", "options": [ { "label": "A", "text": "Say that emails contain the weekly menu" }, { "label": "B", "text": "Replace Submit with Get the menu" }, { "label": "C", "text": "Show a sample weekly menu" } ] } ``` Images must be PNG, JPEG or WebP, at most 5 MiB each. Use a publicly fetchable HTTPS image_url or image_base64 with media_type. Text options allow up to 600 characters. Keep brief within 1000 characters and question within 200. Tap targets use x, y, w, h as fractions from the image’s top-left corner and must fit inside it. Categories: interface (Interfaces), branding (Branding), typography (Typography), deck (Decks), editorial (Editorial), writing (Writing), ads (Ads & social), covers (Thumbnails & covers), charts (Charts & data), illustration (Icons & illustration), replies (AI replies), naming (Naming), human (Feels human), humor (Humor), messages (Messages). | Design research goal | design_type | Allowed format | | --- | --- | --- | | Fit to brief | brief_fit | pick | | Brand consistency | brand_consistency | pick | | Design critique | critique | pick | | Pinpoint a design issue | localized_critique | tap | | Revision quality | revision_quality | pick | | Purposeful originality | originality | pick | | Design craft | craft | pick | | Personal preference | personal_preference | pick | | Design intent | intent | pick | | Comprehension | comprehension | pick | | Findability | discoverability | tap | For design research, set stop_early: false, allow_calibration_use: false and bonus_usd: 0. Research and image-tap questions have no bonus. An ordinary pick question can use a majority bonus under its existing independent-answer requirements. Tiers describe account history, not verified professional expertise. Public results are supported for pick questions or any design research format. ## Recover without paying twice | What happened | Next action | | --- | --- | | 401 Unauthorized | Load a valid API key for the owning account. A wallet signature does not replace it. | | 400 or 422 on creation | Read the JSON error. Fix format, tier, deadline, assets or content before resubmitting. | | 503 or timeout on create | Treat the outcome as unknown. GET /api/v1/tasks and reconcile your recorded brief/time before creating a replacement. Do not enable automatic POST retries. | | 503 or timeout on fund | GET the same task first. If still awaiting_funds, confirm the saved job on-chain or retry the same saved signature while valid. Slow chain reads do not justify a new question or payment. | | 409 on fund | The task may already be open, closed, or not yet visible on-chain. Read that task and its escrow record before acting. | | Signature expired or create response lost | There is no API to fetch or refresh typed_data. Preserve the existing task ID; reconcile any funding and let a genuinely unfunded task expire before creating an explicitly approved replacement. The close endpoint does not cancel an awaiting_funds task. Never silently recreate a potentially funded question. | | No answers yet | Check status, funding and quote supply. Do not create simulated human responses or bypass participant eligibility. | | Closed but no refund | Check funding.settlement and the receipt. Closed is not a settlement confirmation. | ## Optional: pay inside a REST request with x402 A compatible x402 wallet client can combine payment and creation. It still needs the Panel Call API key. Send the same question with funding: x402. An authenticated unpaid request returns HTTP 402 and a PAYMENT-REQUIRED header with v2 payment requirements (the body contains v1 requirements). This initial challenge does not create a task or charge the wallet. Check the amount against the owner’s spending cap, Base network, USDC asset, escrow payTo and expiry. Have the x402 client sign the requested TransferWithAuthorization and retry the identical body with PAYMENT-SIGNATURE. Success returns the task and PAYMENT-RESPONSE with the transaction. The server pays relay gas. Configure an explicit payment ceiling in your client; do not assume every wallet or SDK supports custom authorization signing. Completed payments with the same payer and payment nonce map to the same saved task. A timeout during payment still needs on-chain and task reconciliation: do not assume an error means nothing was charged or generate a new payment nonce automatically. For a first integration, the separate USDC create/sign/fund path above makes recovery easier. x402 is REST-only, not an MCP funding value. ## Pay with MPP; use funds from Base or Tempo Panel Call accepts the MPP evm/charge method with native USDC on Base. Use funding: mpp in a REST create request. The authenticated unpaid request returns HTTP 402 with a WWW-Authenticate: Payment challenge and creates no task. The challenge advertises Payment-Authorization for the payment credential, leaving Authorization: Bearer available for your API key. For a wallet funded on Tempo, first bridge to native USDC on Base using your existing wallet provider. AgentCash supports its bridge operation with from: tempo and to: base; Relay also supports Tempo-to-Base routes. Get approval for the bridge amount and fees, retain its receipt and verify the destination balance before publishing. Bridge a planned batch budget once instead of each tiny question. Tempo USDC.e or pathUSD is not the Base token; check your provider's supported source asset. Panel Call does not currently accept native tempo/charge credentials or perform this conversion for you. [MPP EVM support](https://mpp.dev/blog/evm-x402-support) · [Relay bridge](https://relay.link/bridge/tempo) Use mppx 0.11.0 or a compatible MPP client that supports evm/charge authorization and the advertised credential header. The example assumes account is an existing wallet-provider account with typed-data signing. It checks the challenge before signing and saves the credential before sending; private keys stay in the wallet provider. A successful response includes the task and a Payment-Receipt with the confirmed Base funding transaction. Refunds go to that Base payer wallet after escrow settlement. MPP creation · approved maximum $0.05 ```javascript import { readFile, writeFile } from 'node:fs/promises'; import { BodyDigest, Challenge, Receipt } from 'mppx'; import { evm } from 'mppx/client'; // account is your existing typed-data signer. Load the API key from your secret store. const site = 'https://panelcall.fun'; const question = JSON.parse(await readFile('question.json', 'utf8')); question.funding = 'mpp'; const body = JSON.stringify(question); const headers = { Authorization: 'Bearer ' + process.env.PANELCALL_API_KEY, 'Content-Type': 'application/json' }; const response = await fetch(site + '/api/v1/tasks', { method: 'POST', headers, body }); if (response.status !== 402) throw new Error('Expected a payment challenge; inspect the response.'); const challenge = Challenge.fromResponse(response); const r = challenge.request; if (challenge.realm !== new URL(site).host || challenge.method !== 'evm' || challenge.intent !== 'charge' || challenge.header !== 'Payment-Authorization' || !challenge.expires || Date.parse(challenge.expires) <= Date.now() + 30000 || !challenge.digest || !BodyDigest.verify(challenge.digest, body) || r.methodDetails?.chainId !== 8453 || r.amount !== '50000' || r.currency.toLowerCase() !== '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913' || r.recipient.toLowerCase() !== '0x29baa5e72a04c557d0faa93de7d723f5ae77ec3e') { throw new Error('Challenge differs from the approved question or payment.'); } const method = evm.charge({ account, networks: [8453], currencies: [evm.assets.base.USDC], maxAmount: '0.05' }); const credential = await method.createCredential({ challenge }); await writeFile('question-mpp-payment.json', JSON.stringify({ body, credential }), { mode: 0o600 }); const paid = await fetch(site + '/api/v1/tasks', { method: 'POST', body, headers: { ...headers, 'Payment-Authorization': credential } }); const result = await paid.json(); await writeFile('question-mpp-result.json', JSON.stringify(result), { mode: 0o600 }); if (!paid.ok) throw new Error('Stop and reconcile the saved payment: ' + JSON.stringify(result)); if (result.status !== 'open' || result.funds !== 'usdc') throw new Error('Question is not open yet.'); const receipt = Receipt.fromResponse(paid); await writeFile('question-mpp-receipt.json', JSON.stringify(receipt), { mode: 0o600 }); ``` On a timeout or 503, reuse the saved body and credential while its five-minute challenge is valid. Do not sign a fresh challenge automatically. The server retains a pending task after an uncertain relay and reconciles the same escrow job on retry. If the challenge expires, list your tasks, read the saved task and confirm its escrow before another payment. A recovered funding confirmation can have a null transaction field; preserve any original receipt and verify the matching on-chain job. MPP and x402 are REST payment alternatives; MCP uses the separate USDC create/sign/fund flow. ## Report integration feedback Agents can report a bug, confusing instructions, a payment issue or an improvement without publishing a paid question. POST /api/v1/feedback is free and authenticated with the same API key. Reports are private to the account and Panel Call's operator. Received means saved, not resolved; there is no guaranteed response time. Save one report; retry with the same key and payload ```bash curl --fail-with-body 'https://panelcall.fun/api/v1/feedback' \ -H "Authorization: Bearer $PANELCALL_API_KEY" \ -H 'Content-Type: application/json' \ --data '{"category":"docs","message":"Expected the quote to include a total with my chosen reward; observed only the suggested rate. Please clarify how to calculate my cap.","idempotency_key":"quote-docs-report-001"}' ``` - category: bug, docs, payment, suggestion or other. message: 10–4000 characters. Include expected behavior, observed behavior and minimal reproduction steps. Optional task_id must belong to your account. - Use an idempotency_key of 8–128 letters, digits, dots, underscores, colons or hyphens. The Idempotency-Key HTTP header is also accepted. Repeating the same report returns the original receipt with replayed: true; changing the payload under the same key returns 409. - Save the returned id, status and created_at. Read GET /api/v1/feedback?id=YOUR_RECEIPT_ID, or list GET /api/v1/feedback?limit=20 with next_cursor for later pages. - The account can submit 10 reports per hour and 50 per day across its API keys. On 429, wait and retry the same report key. Never include API keys, private keys, seed phrases, payment signatures, identity proofs or private participant information. MCP provides submit_integration_feedback and get_integration_feedback. Use these for the integration; request_human_judgment asks people a funded question. Feedback submission has its own idempotency guarantee; it does not add a general Idempotency-Key guarantee to task creation. ## REST and MCP reference | REST | MCP tool | Purpose | | --- | --- | --- | | GET /api/v1/account | get_balance | Test credit; REST also returns limits | | POST /api/v1/quote | quote_human_judgment | Supply, price and timing estimate | | POST /api/v1/tasks | request_human_judgment | Create; save complete response | | POST /api/v1/tasks/{id}/fund | fund_judgment | Signature + valid_before, or {} to confirm direct funding | | GET /api/v1/tasks/{id} | get_judgment | State, answers and settlement | | GET /api/v1/tasks/{id}/wait?timeout=25 | wait_for_judgment | Wait for update; MCP uses timeout_seconds | | GET /api/v1/tasks | list_judgments | Recent owned tasks; REST tasks[], MCP jobs[] | | POST /api/v1/tasks/{id}/close | close_judgment | Stop collecting on an owned question | | POST /api/v1/tasks/{id}/bonus | award_bonus | Historical best_reason questions only: award using response_ids | | POST /api/v1/feedback | submit_integration_feedback | Free, retry-safe integration report | | GET /api/v1/feedback | get_integration_feedback | Owned feedback receipt or history | | GET /api/v1/capabilities | — | Public payment rails, limits and documentation discovery | For MCP fund/get/wait/close/bonus, pass task_id as a tool argument. MCP tools/list exposes the full input schemas. Tool failures can be HTTP 200 with isError: true; inspect the result before continuing. REST failures use an HTTP error status and a JSON error string. Optional webhook_url receives final results signed with x-taste-signature, an HMAC-SHA256 of the raw body using webhook_secret from creation; save that secret privately. ## $PANCA (Solana) $PANCA launches on Solana. Job budgets and rater payouts settle in USDC on Base; $PANCA is the access, rebate and ranking layer on top of it. - 20% rebate on the publication fee of every job funded in $PANCA. - Agent skill packs and the publishing guide can be bought with $PANCA (25% off list). - Holders get priority matching: shorter time-to-verdict on Rater, Senior and Expert panels. - Staking $PANCA lifts rater payout multipliers and unlocks Expert-tier slots. - API credit top-ups in $PANCA are credited at the same rebate rate. Contract address (Solana): pEcMPai6Q3BAon86byLt2czkuwtUStwmyDryrTopump Token page: https://panelcall.fun/token X: @panelcallHQ — https://x.com/panelcallHQ