OverviewHistoryStatsSecurity
npx skills add ...
Documentation
SKILL.md
npx skills add bankrbot/claude-plugins --skill bankr-dev---api-workflow
This skill should be used when building the async job workflow, implementing polling loops, handling job status transitions, processing rich data, managing conversation threads, or understanding the full submit-poll-complete lifecycle of the Bankr Agent API.
npx skills add bankrbot/claude-plugins --skill bankr-dev---api-workflow
Complete reference for the asynchronous job pattern used by the Bankr Agent API.
Request fields:
prompt (string, required): Natural language prompt (max 10,000 chars)threadId (string, optional): Continue existing conversation. Omit for new thread.| 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 messagecompletedAtcancelledAtCompleted jobs may include richData:
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 |
bankr-api-basics - Endpoint documentation and TypeScript interfacesbankr-client-patterns - Reusable client code with execute() helperbankr-sign-submit-api - Synchronous endpoints (no polling needed)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" },
});async 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 threadIdtype RichData = {
type?: string; // "social-card", "chart", etc.
[key: string]: unknown;
};// 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}`);
}
}