PersonalBusinessEnterprise
    In a rush? Schedule an Appointment
    Fetching local time...
    Anytime CapitalforBusiness
    Pricing

    Get started

    • Overview
    • Quickstart
    • Test mode
    • Guides & recipes
    • Switch from Stripe
    • Import from Shopify
    • Import from WooCommerce
    • Import from Square
    • Import a CSV file
    • Stripe API mapping
    • Pricing
    • Support
    • FAQ

    Payments

    • Checkout & website
    • Guide: Next.js checkout
    • In person (QR)
    • Payment methods
    • Stablecoin checkout
    • Guide: take stablecoins
    • Fraud rules & 3D Secure
    • Dispute evidence
    • International customers
    • Guide: safe refunds
    • Bank transfers on invoices

    Billing

    • Subscription discounts
    • Guide: sell subscriptions
    • Usage billing
    • Guide: report usage

    Money movement

    • Payout options
    • Guide: reconcile payouts
    • Accounting sync
    • Revenue analytics

    Developers

    • Authentication
    • Errors & retries
    • Pagination
    • Idempotency
    • Rate limits
    • Webhooks
    • Verify webhooks
    • Node SDK (preview)
    • CLI (preview)
    • Postman collection

    AI

    • AI agents hub
    • Safe AI agents
    • Custom agents
    • Prompt library

    Integrations

    • Website builders
    • Shopify
    • Shopify orders by invoice
    • WooCommerce
    • Zapier
    • Slack, Discord and Teams

    Reference

    • Payments
    • Refunds
    • Disputes
    • Payment links
    • Invoices
    • Customers
    • Products
    • Subscriptions & plans
    • Discount codes
    • Meters & usage events
    • Payouts & balance
    • Webhook endpoints
    • Events
    • Test helpers
    • OpenAPI spec
    • Error codes
    • Changelog
    • Glossary

    For AI tools

    • llms-full.txt
    • MCP server
    • openapi.json
    Docs menu · Guide: reconcile payouts

    Get started

    • Overview
    • Quickstart
    • Test mode
    • Guides & recipes
    • Switch from Stripe
    • Import from Shopify
    • Import from WooCommerce
    • Import from Square
    • Import a CSV file
    • Stripe API mapping
    • Pricing
    • Support
    • FAQ

    Payments

    • Checkout & website
    • Guide: Next.js checkout
    • In person (QR)
    • Payment methods
    • Stablecoin checkout
    • Guide: take stablecoins
    • Fraud rules & 3D Secure
    • Dispute evidence
    • International customers
    • Guide: safe refunds
    • Bank transfers on invoices

    Billing

    • Subscription discounts
    • Guide: sell subscriptions
    • Usage billing
    • Guide: report usage

    Money movement

    • Payout options
    • Guide: reconcile payouts
    • Accounting sync
    • Revenue analytics

    Developers

    • Authentication
    • Errors & retries
    • Pagination
    • Idempotency
    • Rate limits
    • Webhooks
    • Verify webhooks
    • Node SDK (preview)
    • CLI (preview)
    • Postman collection

    AI

    • AI agents hub
    • Safe AI agents
    • Custom agents
    • Prompt library

    Integrations

    • Website builders
    • Shopify
    • Shopify orders by invoice
    • WooCommerce
    • Zapier
    • Slack, Discord and Teams

    Reference

    • Payments
    • Refunds
    • Disputes
    • Payment links
    • Invoices
    • Customers
    • Products
    • Subscriptions & plans
    • Discount codes
    • Meters & usage events
    • Payouts & balance
    • Webhook endpoints
    • Events
    • Test helpers
    • OpenAPI spec
    • Error codes
    • Changelog
    • Glossary

    For AI tools

    • llms-full.txt
    • MCP server
    • openapi.json
    DocsMoney movementGuide: reconcile payouts

    Reconcile payments and payouts nightly

    A nightly job that pulls a day's payments, refunds and payouts from the Anytime Capital API, writes a CSV, matches payouts to your bank and flags problems.

    View as MarkdownOpen in Claude

    Once a day, pull what happened from the API, write it down, and check it against your bank: payments in, refunds out, and payouts to your bank with their trace numbers. The script below does that for one UTC day and exits non-zero when something needs a person, so your scheduler can alert you.

    A read-only key

    Create a key with Read only access, or Custom with payments, refunds and payouts set to read. A reporting job never needs to write. See Authentication.

    The script

    reconcile.mjs
    // reconcile.mjs — Node.js 18+. Run nightly for yesterday (UTC), or: node reconcile.mjs 2026-10-23
    import { writeFile } from "node:fs/promises";
    
    const API = "https://anytime-capital.com/api/v1";
    const headers = { Authorization: `Bearer ${process.env.ANYTIME_API_KEY}` };
    const DAY_MS = 86_400_000;
    
    /** GET with retries on 429 and 5xx (reads are always safe to repeat). */
    async function get(path) {
      for (let attempt = 1; ; attempt++) {
        const res = await fetch(`${API}${path}`, { headers });
        const body = await res.json().catch(() => ({}));
        if (res.ok) return body;
        if ((res.status === 429 || res.status >= 500) && attempt < 4) {
          const wait = Number(res.headers.get("Retry-After") ?? 2 ** attempt);
          await new Promise((resolve) => setTimeout(resolve, wait * 1000));
          continue;
        }
        throw new Error(`GET ${path}: ${body.error?.code}: ${body.error?.message}`);
      }
    }
    
    /** Every object of a list, newest first, until `stop` says we've gone back far enough. */
    async function* walk(path, params = {}, stop = () => false) {
      let cursor = null;
      do {
        const query = new URLSearchParams({ ...params, limit: "100", ...(cursor ? { cursor } : {}) });
        const page = await get(`${path}?${query}`);
        for (const item of page.data) {
          if (stop(item)) return;
          yield item;
        }
        cursor = page.hasMore ? page.nextCursor : null;
      } while (cursor);
    }
    
    const day = process.argv[2] ?? new Date(Date.now() - DAY_MS).toISOString().slice(0, 10);
    const from = new Date(`${day}T00:00:00Z`);
    const to = new Date(from.getTime() + DAY_MS);
    const inDay = (iso) => new Date(iso) >= from && new Date(iso) < to;
    const before = (item) => new Date(item.createdAt) < from;
    
    // Payments filter by date on the server; refunds and payouts are newest first, so stop past the day.
    const payments = [];
    for await (const payment of walk("/payments", { createdFrom: day, createdTo: to.toISOString().slice(0, 10) })) {
      payments.push(payment);
    }
    const refunds = [];
    for await (const refund of walk("/refunds", {}, before)) if (inDay(refund.createdAt)) refunds.push(refund);
    const payouts = [];
    for await (const payout of walk("/payouts", {}, before)) if (inDay(payout.createdAt)) payouts.push(payout);
    const balance = await get("/balance");
    
    const paid = payments.filter((payment) => payment.paidAt !== null);
    const sum = (items, field) => items.reduce((total, item) => total + (item[field] ?? 0), 0);
    const usd = (cents) => (cents / 100).toFixed(2);
    
    const problems = [
      ...paid.filter((payment) => payment.netCents === null).map((payment) => `${payment.id}: net not reported yet`),
      ...refunds.filter((refund) => refund.status === "failed").map((refund) => `${refund.id}: refund failed (${refund.failureReason})`),
      ...payouts
        .filter((payout) => ["failed", "reversed", "denied", "canceled"].includes(payout.status))
        .map((payout) => `${payout.id}: payout ${payout.status}: ${payout.failureMessage ?? ""}`),
    ];
    
    // One CSV row per record, for your spreadsheet or accounting import.
    const rows = [
      ["type", "id", "status", "amount_cents", "net_cents", "reference", "created_at"],
      ...payments.map((p) => ["payment", p.id, p.status, p.amountCents, p.netCents ?? "", p.metadata?.orderId ?? p.clientReference ?? "", p.createdAt]),
      ...refunds.map((r) => ["refund", r.id, r.status, -r.amountCents, "", r.paymentId, r.createdAt]),
      ...payouts.map((p) => ["payout", p.id, p.status, p.amountCents ?? "", p.netCents ?? "", p.traceCode ?? "", p.createdAt]),
    ];
    const csv = rows.map((row) => row.map((cell) => `"${String(cell).replace(/"/g, '""')}"`).join(",")).join("\n");
    await writeFile(`reconciliation-${day}.csv`, `${csv}\n`);
    
    console.log(`${day}: ${paid.length} payments, $${usd(sum(paid, "amountCents"))} gross, $${usd(sum(paid, "netCents"))} net`);
    console.log(`refunds: ${refunds.length}, $${usd(sum(refunds.filter((r) => r.status !== "failed"), "amountCents"))}`);
    for (const payout of payouts) {
      console.log(`payout ${payout.id} ${payout.status} $${usd(payout.netCents ?? 0)} trace ${payout.traceCode ?? "-"} arrives ${payout.estimatedArrival ?? "-"}`);
    }
    console.log(`balance now: $${usd(balance.availableCents)} available, $${usd(balance.pendingCents)} pending, $${usd(balance.reserveCents)} reserve`);
    if (problems.length > 0) {
      console.error(`Needs a look:\n${problems.join("\n")}`);
      process.exitCode = 1;
    }

    Run it every night

    crontab (Node.js 20.6+ reads .env with --env-file)
    # 06:15 UTC every day, for the day before
    15 6 * * * cd /srv/reconcile && node --env-file=.env reconcile.mjs >> reconcile.log 2>&1

    Match payouts to your bank

    • Each payout's netCents is what reaches your bank, and traceCode is the trace number your bank can find the deposit by: match on the amount, and on the trace number where your bank shows it.
    • estimatedArrival says when to expect it. A payout that is completed but not in your bank a day after that is worth a call to Support.
    • payout.paid and payout.failed webhooks tell you as it happens, if you'd rather not wait for the night.

    What the API doesn't tell you

    The API doesn't say which payments make up each payout: Payouts in the dashboard shows that, payout by payout. To have every payment, card processing charge, refund and payout booked for you, use Accounting sync with QuickBooks Online or Xero, which posts them through a clearing account so the payouts match your bank feed.

    PreviousPayout optionsNext Accounting sync

    Anytime Capital is a fintech company, not a bank. Payment processing, banking and payout services are provided by Anytime Capital's licensed partners. Rates shown are for US card payments; international cards, currency conversion and disputes may carry additional fees shown in your dashboard before you accept a payment.

    On this page

    • The script
    • Run it every night
    • Match payouts to your bank
    Anytime Capital
    (470) 748-2530
    App Store

    Business

    • Business Checking
    • Business Debit Cards
    • Payments
    • Ecommerce Payments
    • Invoicing
    • Developer Docs

    Solutions

    • CPAs & Accountants
    • Financial Advisors
    • Boat & Auto Dealerships
    • Dental & Medical Practices
    • Creators & Coaches
    • All solutions

    Crypto

    • Crypto Wallet
    • Tether Wallet
    • Buy Digital Assets
    • Explore Markets
    • Security & Licenses
    • Compare Platforms
    • Bitcoin ATM Alternative

    Company

    • Our Story
    • Schedule Appointment
    • Careers
    • Media & Press
    • Investor Relations
    • FAQ

    Branches

    • Atlanta, Georgia
    • Miami, Florida
    • Houston, Texas
    • All branches

    Legal

    • Terms & Conditions
    • Privacy Policy
    • Your Privacy Choices
    • Fraud Notice

    © 2026 Anytime Capital LLC. Anytime Capital is a fintech company, not a bank.

    The Anytime Capital Mastercard® Prepaid Card is issued by Pathward®, N.A., Member FDIC. Mastercard® is a registered trademark of Mastercard International Incorporated. All other trademarks and service marks belong to their respective owners.

    Mastercard