Install
openclaw skills install @jan-blockbites/payaion-transferTransfer files via the Payaion REST API, set USDC per-download pricing on Base mainnet, and list on the marketplace. Use for agent-to-human, agent-to-agent, and agent-to-marketplace file flows.
openclaw skills install @jan-blockbites/payaion-transferAudience: OpenClaw agents installed from ClawHub. This skill is curl/REST-only. For Cursor or Claude Code, use the separate
payaion-agentskill (MCP-first).Previously published as AgentVee Transfer, which passed 600+ downloads during the testnet phase. This is the production release: Base mainnet, live USDC, and
PAYAION_API_KEYin place ofAGENTVEE_API_KEY.
Transfer files between agents and humans. Upload from URL or local disk, set per-download pricing in USD (settled in USDC on Base mainnet), list on the Payaion marketplace, and share download links — all via the Payaion REST API.
| API | https://payaion-api.fly.dev |
| Web | https://payaion.com |
| Chain | Base mainnet · USDC |
| Auth header | X-Aion-Key: $PAYAION_API_KEY |
No API key needed to transfer. Omit the X-Aion-Key header entirely and the
upload runs as a guest: 100 MB per file, 24-hour link, no account. A key raises the
limits (500 MB, 2 GB stored, 28-day links). You can sell without a key too — see
X-Payout-Address below.
Get one at payaion.com/dashboard, or have the agent mint its own by signing a message with a wallet it holds locally — three requests, no browser: payaion.com/docs/agent-flow.
Earnings go to a payout address set in the dashboard. No API key can read or change it, so a compromised agent key costs uploads, not money.
Three supported flows:
| Flow | Description |
|---|---|
| Agent → Human | Upload a file, share the download link |
| Agent → Agent | Upload + share the uploadId or download URL |
| Agent → Marketplace | Upload with pricing, list publicly for paid downloads |
Optional for transfers. Send the header when a key is set, omit it entirely when it is not — the upload then runs as a guest.
X-Aion-Key: $PAYAION_API_KEY # omit this line if PAYAION_API_KEY is unset
Listing on the marketplace and buying still require a key. Both fail with 403 insufficient_scope or forbidden without one.
Base URL (production): https://payaion-api.fly.dev
Upload + wait for ready + set price + list on marketplace — all in ONE curl call. The server handles polling internally and returns the final result.
curl -s -X POST https://payaion-api.fly.dev/v1/aion/upload \
-H "X-Aion-Key: $PAYAION_API_KEY" \
-H "X-Wait-For-Ready: true" \
-H "X-Price-Per-Download: 0.25" \
-H 'X-Listing-Intent: {"title":"My Report","description":"Market analysis","category":"reports","tags":["market","analysis"]}' \
-F "file=@/path/to/file.pdf"
curl -s -X POST https://payaion-api.fly.dev/v1/aion/upload-url \
-H "X-Aion-Key: $PAYAION_API_KEY" \
-H "X-Wait-For-Ready: true" \
-H "X-Price-Per-Download: 0.25" \
-H 'X-Listing-Intent: {"title":"My Report","description":"Market analysis","category":"reports","tags":["market","analysis"]}' \
-H "Content-Type: application/json" \
-d '{"url": "URL_HERE"}'
{
"uploadId": "up_a1b2c3d4e5f6g7h8",
"status": "READY",
"ready": true,
"downloadUrl": "https://payaion.com/d/abc123xyz789",
"expiresAt": "2026-04-10T12:00:00.000Z",
"pricePerDownload": "0.25",
"url": "https://payaion.com/m/abc123xyz789"
}
202 means the file was accepted but is still processing — the server either had no
wait slot free or wait mode is off ("waitUnavailable": true). This is the only
case where polling is allowed: call the status endpoint below every few seconds until
ready is true (give up after ~2 minutes and report the last status).
| Header | Required | Description |
|---|---|---|
X-Aion-Key | No | API key. Omit it to upload as a guest; required to list or buy |
X-Wait-For-Ready | Always send | true — server waits until the file is READY (up to ~120s) and returns 200 |
X-Price-Per-Download | No | Price in USD (e.g. 0.25). Omit for free downloads. Above 0 requires a connected wallet |
X-Listing-Intent | No | JSON string with marketplace listing data. Server auto-lists after READY. Needs a key with the marketplace:list scope — a keyless caller is refused with 403 |
X-Payout-Address | No | Keyless sellers only: the wallet a priced download pays out to (0x…, 40 hex characters). This is what lets an agent sell with no account. Ignored when a key is sent, because that account's payout address is a dashboard setting |
{
"title": "string (3–120 chars, required)",
"description": "string (40–500 chars, REQUIRED — what the buyer gets)",
"category": "reports|datasets|code|media|models|prompts|other",
"tags": ["tag1", "tag2"]
}
description is required and must be at least 40 characters. A shorter or missing description fails the whole request with 422. Write a real sentence or two about what the buyer gets — never a placeholder.X-Payout-Address when uploading without a key. Otherwise the request fails with 400 wallet_required.If the user doesn't specify title/description/category/tags, generate them from the filename and context.
curl -s "https://payaion-api.fly.dev/v1/aion/marketplace/browse" \
-H "X-Aion-Key: $PAYAION_API_KEY"
With filters:
curl -s "https://payaion-api.fly.dev/v1/aion/marketplace/browse?q=oil&category=reports&page=1&pageSize=10" \
-H "X-Aion-Key: $PAYAION_API_KEY"
| Param | Type | Default | Description |
|---|---|---|---|
q | string | — | Search title and description (max 100 chars) |
category | string | — | Filter: reports, datasets, code, media, models, prompts, other |
page | int | 1 | Page number (1–100) |
pageSize | int | 20 | Results per page (1–100) |
{
"listings": [
{
"uploadId": "up_a1b2c3d4e5f6g7h8",
"title": "Oil Market Analysis",
"description": "Crude oil trends",
"category": "reports",
"tags": ["oil", "market"],
"fileName": "oil-market-analysis.pdf",
"mimeType": "application/pdf",
"sizeBytes": 51200,
"pricePerDownload": "0.25",
"sellerAddress": "0x7811…ac55",
"listedAt": "2026-03-27T01:30:00.000Z",
"url": "https://payaion.com/m/BiMHwpOqTrxa"
}
],
"total": 1,
"page": 1,
"pageSize": 20
}
url — the market listing page (/m/<hash>), where a buyer sees the description and pricecurl -s https://payaion-api.fly.dev/v1/upload/UPLOAD_ID/status \
-H "X-Aion-Key: $PAYAION_API_KEY"
curl -s -X POST https://payaion-api.fly.dev/v1/upload/UPLOAD_ID/download-url \
-H "X-Aion-Key: $PAYAION_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
curl -s -X DELETE https://payaion-api.fly.dev/v1/upload/UPLOAD_ID/delete \
-H "X-Aion-Key: $PAYAION_API_KEY"
Folders group what the account already holds. They are metadata, not storage: a move never touches the file, and deleting a folder keeps every file inside it — the files drop back to the storage root with their share link, price and expiry unchanged. Deleting a file is the separate call above.
Nesting stops at 8 levels, sibling names must be unique and cannot contain slashes, and folders count against no quota. A key is required — a keyless (guest) caller has no storage to organise.
# every folder with its full path and file count, the files at the root,
# and bytes used against the plan limit
curl -s https://payaion-api.fly.dev/v1/storage \
-H "X-Aion-Key: $PAYAION_API_KEY"
# the files inside one folder
curl -s "https://payaion-api.fly.dev/v1/storage?folderId=FOLDER_ID" \
-H "X-Aion-Key: $PAYAION_API_KEY"
curl -s -X POST https://payaion-api.fly.dev/v1/folders \
-H "X-Aion-Key: $PAYAION_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Clients","parentId":null}'
# name, parentId, or both. "parentId": null moves it to the top level.
curl -s -X PATCH https://payaion-api.fly.dev/v1/folders/FOLDER_ID \
-H "X-Aion-Key: $PAYAION_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Clients 2026"}'
curl -s -X DELETE https://payaion-api.fly.dev/v1/folders/FOLDER_ID \
-H "X-Aion-Key: $PAYAION_API_KEY"
# "folderId": null puts it back at the storage root
curl -s -X POST https://payaion-api.fly.dev/v1/files/UPLOAD_ID/move \
-H "X-Aion-Key: $PAYAION_API_KEY" \
-H "Content-Type: application/json" \
-d '{"folderId":"FOLDER_ID"}'
Errors worth reading rather than retrying: 409 a sibling already has that name,
422 the name is invalid, the nesting cap is reached, or the move would put a
folder inside itself, 404 the folder is not yours.
-H "Idempotency-Key: my-unique-key-12345"
Key: 8–64 chars, alphanumeric + hyphens + underscores. Same key → cached response, no duplicate upload.
Requires an API key. The cache is per-caller, and a keyless caller has no stable identity to key it to, so for guest uploads the header is ignored and a retry creates a second upload. Retrying without a key? Check the first attempt's status instead of resending.
You MUST complete the entire flow in a SINGLE curl call. The One-Shot API handles upload + waiting + listing server-side. Do NOT poll manually (the only exception is a 202 response — see above). Do NOT make multiple API calls. Do NOT stop to ask the user mid-flow.
X-Wait-For-Ready, X-Price-Per-Download, X-Listing-Intent)If the user doesn't provide title/description/category/tags, generate them from the filename.
✓ Transfer complete
- Upload ID: up_xxxxx
- Price: $0.25/download
- URL: https://payaion.com/d/... # downloadUrl — share this to send the file
- Market: https://payaion.com/m/... # url — only when listed on the marketplace
- Status: READY
If the response contains "ready": false or an error, report the failure with the exact error message.
{ "error": { "code": "error_code", "message": "Human-readable message" } }
| Status | Code | Action |
|---|---|---|
| 400 | wallet_required | A price above 0 needs a wallet connected to the account. Tell the user to connect one in the dashboard, or retry with no price |
| 400 | invalid_price | X-Price-Per-Download must be a non-negative number in USD, and at least 0.000001 — anything smaller rounds to zero USDC |
| 400 | invalid_payout_address | X-Payout-Address must be a 0x-prefixed 40-character EVM address |
| 403 | password_required | The asset is password-protected. Send the user to its /d/<hash> page, which prompts for the password |
| 429 | priced_upload_limit | Daily cap on priced uploads without an account. Sign in to sell more |
| 429 | rate_limit_exceeded (reason abuse) | The key tripped limits repeatedly and is blocked for retryAfterSec. Stop — do not keep retrying |
| 401 / 403 | unauthorized | Check the API key |
| 403 | insufficient_scope | The key lacks a scope (marketplace:list to sell, marketplace:purchase to buy). Keys minted by wallet signature carry upload scopes only — price files from the dashboard instead |
| 403 | storage_limit_exceeded | The account's total storage is full (Basic 2 GB / Pro 20 GB). Tell the user to delete files or upgrade — do NOT retry, and do not split the file into parts |
| 403 | file_count_limit_exceeded | The account holds too many live files (Basic 200 / Pro 2,000). Tell the user to delete files or upgrade — do NOT retry |
| 413 | size_limit_exceeded | File exceeds the per-file limit for the account's plan (Basic 500 MB / Pro 1 GB). Do NOT retry or chunk it — report the limit |
| 415 | blocked_mime_type | File type not allowed |
| 422 | validation errors | Check field constraints — most often a listing description under 40 characters |
| 429 | rate_limited | Wait retryAfterSec seconds, then retry |
| 502 | upload_worker_unavailable | Retry after the Retry-After header value |
Checked per request against the account's current plan — an expired Pro is back on Basic limits immediately.
X-Wait-For-Ready: true does everything202)~/.ssh, ~/.gnupg, /etc) without explicit user approvalX-Listing-Intent when the user wants marketplace listingIdempotency-Key when retrying failed uploads to avoid duplicatesDELETE /v1/folders/... to delete files — it keeps them and moves them to the root; delete files explicitly when that is what was askedFull OpenAPI 3.1 spec: payaion.com/openapi.yaml
openclaw skills install @jan-blockbites/payaion-transferpayaion-agent instead