Help us improve
Share bugs, ideas, or general feedback.
From bankr-agent-dev
Implements Bankr Agent API async job workflows: submit prompts, poll status every 2s, handle transitions like pending/processing/completed, process rich data/responses, manage threads.
npx claudepluginhub bankrbot/claude-plugins --plugin bankr-agent-devHow this skill is triggered — by the user, by Claude, or both
Slash command
/bankr-agent-dev:bankr-api-workflowThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Complete reference for the asynchronous job pattern used by the Bankr Agent API.
Documents Bankr Agent API endpoints, async submit-poll-complete job pattern, TypeScript examples, and response schemas for crypto trading and market analysis.
Manages async jobs in Bankr x402 SDK: submit prompts, poll status, check completion, cancel jobs, batch process, handle retries and timeouts.
Executes Bankr API operations via MCP tools using submit-poll-complete pattern: submit prompts, poll status every 2s, handle results for trades, prices, and analysis.
Share bugs, ideas, or general feedback.
Complete reference for the asynchronous job pattern used by the Bankr Agent API.
1. SUBMIT -> POST /agent/prompt -> Get jobId + threadId
2. POLL -> GET /agent/job/{id} -> Check status every 2s
3. COMPLETE -> Terminal status -> Process response + richData
const response = await fetch(`${API_URL}/agent/prompt`, {
method: "POST",
headers: { "x-api-key": API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({
prompt: "What is my ETH balance?",
threadId: "thr_XYZ789", // optional: continue conversation
}),
});
// → { success: true, jobId: "job_abc123", threadId: "thr_XYZ789", status: "pending" }
Request fields:
prompt (string, required): Natural language prompt (max 10,000 chars)threadId (string, optional): Continue existing conversation. Omit for new thread.const status = await fetch(`${API_URL}/agent/job/${jobId}`, {
headers: { "x-api-key": API_KEY },
});
const cancel = await fetch(`${API_URL}/agent/job/${jobId}/cancel`, {
method: "POST",
headers: { "x-api-key": API_KEY, "Content-Type": "application/json" },
});
| Status | Description | Action |
|---|---|---|
pending | Job queued, not started | Keep polling |
processing | Job running | Keep polling, show statusUpdates |
completed | Finished successfully | Read response and richData |
failed | Encountered error | Check error field |
cancelled | Was cancelled | No further action |
success, jobId, threadId, status, prompt, createdAtresponse — Natural language textrichData — Array of structured data (charts, social cards)transactions — Array of executed transactionscompletedAt, processingTimestatusUpdates — Array of { message, timestamp }startedAt, cancellableerror — Error messagecompletedAtcancelledAtasync function waitForCompletion(
jobId: string,
onProgress?: (message: string) => void
): Promise<JobStatusResponse> {
const POLL_INTERVAL = 2000; // 2 seconds
const MAX_POLLS = 150; // 5 minutes max
let lastUpdateCount = 0;
for (let i = 0; i < MAX_POLLS; i++) {
const status = await getJobStatus(jobId);
// Report new status updates
if (onProgress && status.statusUpdates) {
for (let j = lastUpdateCount; j < status.statusUpdates.length; j++) {
onProgress(status.statusUpdates[j].message);
}
lastUpdateCount = status.statusUpdates.length;
}
// Terminal states
if (["completed", "failed", "cancelled"].includes(status.status)) {
return status;
}
await new Promise((r) => setTimeout(r, POLL_INTERVAL));
}
throw new Error("Job timed out");
}
// Start a conversation
const first = await submitPrompt("What is the price of ETH?");
const threadId = first.threadId;
// Continue the conversation (agent remembers context)
const second = await submitPrompt("And what about BTC?", threadId);
// Each response includes the same threadId
Completed jobs may include richData:
type RichData = {
type?: string; // "social-card", "chart", etc.
[key: string]: unknown;
};
The response field always has a text summary regardless of richData content.
| Status | Error | Resolution |
|---|---|---|
| 400 | Invalid request / Prompt too long | Check input (max 10,000 chars) |
| 401 | Authentication required | Check API key |
| 403 | Agent API not enabled | Enable at bankr.bot/api |
| 404 | Job not found | Check jobId is correct |
| 429 | Rate limit exceeded | Wait for resetAt timestamp |
// Handle rate limits
if (response.status === 429) {
const error = await response.json();
const waitMs = error.resetAt - Date.now();
console.log(`Rate limited. Resets in ${Math.ceil(waitMs / 60000)} minutes`);
}
import { submitPrompt, waitForCompletion } from "./bankr-client";
async function main() {
// Submit
const { jobId } = await submitPrompt("Swap 0.1 ETH for USDC on Base");
console.log(`Job: ${jobId}`);
// Poll with progress
const result = await waitForCompletion(jobId, (msg) => {
console.log(`Progress: ${msg}`);
});
// Handle result
if (result.status === "completed") {
console.log(result.response);
for (const tx of result.transactions || []) {
console.log(`Transaction: ${tx.type}`);
}
} else if (result.status === "failed") {
console.error(`Failed: ${result.error}`);
}
}
bankr-api-basics - Endpoint documentation and TypeScript interfacesbankr-client-patterns - Reusable client code with execute() helperbankr-sign-submit-api - Synchronous endpoints (no polling needed)