Skip to main content
Follow these patterns to build reliable, performant, and secure integrations with the Yoshi API.

Error handling

Always check the response envelope before accessing data:
const response = await fetch("https://api.yoshi.ai/accounts", {
  headers: { Authorization: `Bearer ${process.env.YOSHI_API_KEY}` },
});

if (!response.ok) {
  const { error, meta } = await response.json();
  console.error(`[${meta.request_id}] ${error.code}: ${error.message}`);
  throw new Error(error.display_message || error.message);
}

const { data } = await response.json();
Include request_id in error logs and support tickets — it lets Yoshi trace exactly what happened.

Retry strategy

StatusRetry?Strategy
429YesWait retry_after seconds, then retry
500YesExponential backoff: 1s, 2s, 4s (max 3 retries)
503YesExponential backoff
400NoFix the request — the input is invalid
401NoCheck your API key
404NoThe resource doesn’t exist
409NoDuplicate idempotency key with different parameters
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.ok) return response;

    if (response.status === 429) {
      const retryAfter = Number(response.headers.get("Retry-After")) || 60;
      await sleep(retryAfter * 1000);
      continue;
    }

    if (response.status >= 500 && attempt < maxRetries) {
      await sleep(1000 * Math.pow(2, attempt));
      continue;
    }

    return response; // Don't retry 4xx errors
  }
}
The SDKs handle retries automatically with configurable maxRetries (default: 2).

Caching

ResourceSafe to cacheDuration
Account metadata (names, types)Yes5–15 minutes
BalancesNoChanges every sync
Transactions listBriefly1–5 minutes
ScoresYes1 hour (recalculated daily)
Recurring streamsYes1 hour
Card products catalogYes24 hours
Never cache balance data — it changes with every sync and users expect current numbers.

Webhook processing

Respond fast, process later:
app.post("/webhooks/yoshi", async (req, res) => {
  // Verify signature
  const event = verifyWebhook(req);

  // Acknowledge immediately
  res.sendStatus(200);

  // Process asynchronously
  await queue.add("process-event", event);
});
Return a 2xx response within 15 seconds. If your handler takes longer, Yoshi marks the delivery as failed and retries.
Idempotent processing: Events can be delivered more than once. Use event.id to deduplicate:
async function processEvent(event) {
  const already = await db.get(`processed:${event.id}`);
  if (already) return;

  await handleEvent(event);
  await db.set(`processed:${event.id}`, true, { ex: 86400 });
}

Security

Never expose API keys client-side. API keys grant full access to the user’s financial data. Always make API calls from a backend server.
❌ fetch("https://api.yoshi.ai/accounts", {
     headers: { Authorization: "Bearer yoshi_3xK9mP..." }
   })  // in browser JavaScript

✅ // Browser calls YOUR backend, which calls Yoshi
   fetch("/api/accounts")
Use environment variables. Don’t hardcode keys in source code:
export YOSHI_API_KEY=yoshi_3xK9mP...
Rotate keys periodically. Create a new key, update your services, then revoke the old one. Multiple active keys are supported for zero-downtime rotation. Verify webhook signatures. Always verify the signature before processing webhook events — otherwise anyone can send fake events to your endpoint.

Rate limit budgeting

Each API key has a limit of 100 requests per minute. If you have multiple services sharing a key:
  • Track usage across services using the X-RateLimit-Remaining header
  • Prioritize user-facing requests over background jobs
  • Use webhooks to reduce polling — each webhook you process replaces multiple poll requests
  • Consider separate keys for different services so they have independent limits
const remaining = Number(response.headers.get("X-RateLimit-Remaining"));
if (remaining < 10) {
  console.warn("Approaching rate limit, throttling background jobs");
  pauseBackgroundJobs();
}

What’s next

Errors

Full error codes reference.

Rate limits

Detailed rate limiting documentation.
Last modified on April 17, 2026