> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blnkfinance.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Dry-run transactions

> Preview a transaction's effect on balances without writing anything to the ledger.

export const RelatedTopics = ({title = "Related topics", items = []}) => {
  if (!items.length) {
    return null;
  }
  return <nav className="related-topics not-prose mt-20 mb-10 flex flex-col" aria-label={title}>
      <p className="related-topics-heading m-0 border-b border-zinc-200 pb-3 text-sm font-medium text-zinc-500 dark:border-white/10 dark:text-zinc-400">
        {title}
      </p>
      <ul className="related-topics-list m-0 mt-3 flex list-none flex-col gap-0.5 p-0">
        {items.map(item => {
    const isExternal = typeof item.href === "string" && (/^https?:\/\//i).test(item.href);
    return <li key={item.href} className="m-0 p-0">
              <a href={item.href} target={isExternal ? "_blank" : undefined} rel={isExternal ? "noopener noreferrer" : undefined} className="related-topics-link group inline-flex items-center gap-2 text-sm font-semibold text-zinc-700 no-underline transition-colors dark:text-zinc-300">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="related-topics-icon shrink-0 text-zinc-400 dark:text-zinc-500" aria-hidden="true">
                  <path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" />
                  <path d="M14 2v4a2 2 0 0 0 2 2h4" />
                  <path d="M10 9H8" />
                  <path d="M16 13H8" />
                  <path d="M16 17H8" />
                </svg>
                <span className="relative top-px transition-colors group-hover:text-[#DD7B1B]">
                  {item.title}
                </span>
              </a>
            </li>;
  })}
      </ul>
    </nav>;
};

export const CtaCallout = props => {
  const {title, buttonLabel, href, trackingEvent, buttonTarget, rel = "noopener noreferrer", children} = props;
  const handleCtaClick = () => {
    if (typeof window === "undefined" || !trackingEvent) {
      return;
    }
    try {
      window.dispatchEvent(new CustomEvent("blnk:docs-cta", {
        detail: {
          name: trackingEvent,
          href
        }
      }));
    } catch {}
    try {
      window.posthog?.capture?.(trackingEvent, {
        href
      });
    } catch {}
    const gaPayload = {
      cta_href: href
    };
    try {
      window.gtag?.("event", trackingEvent, gaPayload);
    } catch {}
    try {
      window.dataLayer = window.dataLayer || [];
      window.dataLayer.push({
        event: trackingEvent,
        ...gaPayload
      });
    } catch {}
  };
  const isExternal = typeof href === "string" && (/^https?:\/\//i).test(href);
  const target = buttonTarget ?? (isExternal ? "_blank" : undefined);
  const linkRel = isExternal ? rel : undefined;
  return <section className="cta-callout not-prose relative my-8 w-full min-w-0 overflow-hidden rounded-xl border border-zinc-200 p-5 dark:border-white/10">
      <div className="cta-callout-noise" aria-hidden="true" />
      <div className="cta-callout-layout">
        {title ? <div className="cta-callout-title-row">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28 28" width="14" height="14" className="cta-callout-icon shrink-0 text-zinc-800 dark:text-zinc-200" aria-hidden="true">
              <g fill="none" fillRule="nonzero">
                <path d="M28 0v28H0V0h28ZM14.691833333333335 27.134333333333334l-0.012833333333333334 0.0023333333333333335 -0.08283333333333333 0.04083333333333334 -0.023333333333333334 0.004666666666666667 -0.016333333333333335 -0.004666666666666667 -0.08283333333333333 -0.04083333333333334c-0.011666666666666667 -0.004666666666666667 -0.022166666666666668 -0.0011666666666666668 -0.028000000000000004 0.005833333333333334l-0.004666666666666667 0.011666666666666667 -0.019833333333333335 0.49933333333333335 0.005833333333333334 0.023333333333333334 0.011666666666666667 0.015166666666666667 0.12133333333333333 0.08633333333333333 0.0175 0.004666666666666667 0.014000000000000002 -0.004666666666666667 0.12133333333333333 -0.08633333333333333 0.014000000000000002 -0.018666666666666668 0.004666666666666667 -0.019833333333333335 -0.019833333333333335 -0.4981666666666667c-0.0023333333333333335 -0.011666666666666667 -0.0105 -0.019833333333333335 -0.019833333333333335 -0.021Zm0.3091666666666667 -0.13183333333333336 -0.015166666666666667 0.0023333333333333335 -0.21583333333333335 0.1085 -0.011666666666666667 0.011666666666666667 -0.0035000000000000005 0.012833333333333334 0.021 0.5016666666666667 0.005833333333333334 0.014000000000000002 0.009333333333333334 0.008166666666666668 0.23450000000000004 0.1085c0.014000000000000002 0.004666666666666667 0.026833333333333334 0 0.03383333333333334 -0.009333333333333334l0.004666666666666667 -0.016333333333333335 -0.03966666666666667 -0.7163333333333334c-0.0035000000000000005 -0.014000000000000002 -0.011666666666666667 -0.023333333333333334 -0.023333333333333334 -0.025666666666666667Zm-0.8341666666666667 0.0023333333333333335a0.026833333333333334 0.026833333333334334 0 0 0 -0.0315 0.007000000000000001l-0.007000000000000001 0.016333333333333335 -0.03966666666666667 0.7163333333333334c0 0.014000000000000002 0.008166666666666668 0.023333333333333334 0.019833333333333335 0.028000000000000004l0.0175 -0.0023333333333333335 0.23450000000000004 -0.1085 0.011666666666666667 -0.009333333333333334 0.004666666666666667 -0.012833333333333334 0.019833333333333335 -0.5016666666666667 -0.0035000000000000005 -0.014000000000000002 -0.011666666666666667 -0.011666666666666667 -0.21466666666666667 -0.10733333333333334Z" strokeWidth="1.1667" />
                <path fill="currentColor" d="M14 2.916666666666667A1.75 1.75 0 0 1 15.750000000000002 4.666666666666667v6.302333333333334L21.207666666666668 7.816666666666667a1.75 1.75 0 0 1 1.75 3.031L17.5 14l5.457666666666667 3.151166666666667a1.75 1.75 0 0 1 -1.75 3.031l-5.457666666666667 -3.1500000000000004V23.333333333333336a1.75 1.75 0 0 1 -3.5 0v-6.302333333333334L6.792333333333334 20.183333333333337a1.75 1.75 0 1 1 -1.75 -3.031L10.5 14 5.042333333333334 10.848833333333333a1.75 1.75 0 0 1 1.75 -3.031l5.457666666666667 3.1500000000000004V4.666666666666667A1.75 1.75 0 0 1 14 2.916666666666667Z" strokeWidth="1.1667" />
              </g>
            </svg>
            <p className="cta-callout-title min-w-0 font-semibold text-zinc-800 dark:text-zinc-200">
              {title}
            </p>
          </div> : null}
        <div className={`cta-callout-body text-sm leading-normal text-zinc-800 dark:text-zinc-200${title ? " cta-callout-body--indented" : ""}`}>
          {children}
        </div>
        <a href={href} target={target} rel={linkRel} onClick={handleCtaClick} data-docs-cta={trackingEvent || undefined} className="cta-callout-button inline-flex items-center justify-center gap-1 rounded-full bg-white px-3 py-1.5 text-sm font-semibold transition hover:bg-zinc-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white/50 dark:bg-white dark:hover:bg-zinc-200">
          {buttonLabel}
          <span className="cta-callout-button-arrow" aria-hidden="true">
            →
          </span>
        </a>
      </div>
    </section>;
};

<Info>Available in version 0.15.3 and later.</Info>

A dry run answers whether a transaction would apply and what the source and destination balances would become. Nothing is written: no transaction, no queue entry, no webhook, and no new `@` balance. You can reuse the same `reference` on a real post afterwards.

Send the same request you would use to record the transaction, and set `dry_run` to `true`. Blnk runs the same balance arithmetic a real post uses, then returns a projection.

Use a dry run to check funds, overdraft rules, or split math before you post. It is a snapshot of balances as they stand now.

***

## Dry-run a transaction

Call [Dry-run a transaction](/reference/dry-run) with the same body as [Record a transaction](/reference/create-transaction), plus `"dry_run": true`.

<Tip>
  The same `dry_run` flag works on [bulk create](/reference/bulk-transactions), [refund](/reference/refund-transaction), and [commit or void inflight](/reference/update-inflight).
</Tip>

<CodeGroup>
  ```bash cURL wrap theme={"system"}
  curl -X POST "http://localhost:5001/transactions" \
    -H "X-blnk-key: <api-key>" \
    -H "Content-Type: application/json" \
    -d '{
      "dry_run": true,
      "precise_amount": 12000,
      "precision": 100,
      "reference": "ref_card_settle_4821",
      "currency": "USD",
      "source": "bln_source-bal-001",
      "destination": "bln_dest-bal-001",
      "description": "Card settlement"
    }'
  ```
</CodeGroup>

The response is always HTTP `200` when the preview itself succeeds. A projected rejection is not an HTTP error.

```json 200 OK wrap expandable theme={"system"}
{
  "dry_run": true,
  "would_apply": true,
  "status": "APPLIED",
  "reference": "ref_card_settle_4821",
  "currency": "USD",
  "amount": 120,
  "precise_amount": "12000",
  "precision": 100,
  "balances": [
    {
      "balance_id": "bln_source-bal-001",
      "role": "source",
      "currency": "USD",
      "current_balance": "50000",
      "current_available": "50000",
      "current_credit_balance": "50000",
      "current_debit_balance": "0",
      "current_inflight_debit_balance": "0",
      "current_inflight_credit_balance": "0",
      "resulting_balance": "38000",
      "resulting_available": "38000",
      "resulting_credit_balance": "50000",
      "resulting_debit_balance": "12000",
      "resulting_inflight_debit_balance": "0",
      "resulting_inflight_credit_balance": "0"
    },
    {
      "balance_id": "bln_dest-bal-001",
      "role": "destination",
      "currency": "USD",
      "current_balance": "0",
      "current_available": "0",
      "current_credit_balance": "0",
      "current_debit_balance": "0",
      "current_inflight_debit_balance": "0",
      "current_inflight_credit_balance": "0",
      "resulting_balance": "12000",
      "resulting_available": "12000",
      "resulting_credit_balance": "12000",
      "resulting_debit_balance": "0",
      "resulting_inflight_debit_balance": "0",
      "resulting_inflight_credit_balance": "0"
    }
  ]
}
```

Things to note:

* There is no `transaction_id`. Nothing was written, so the `reference` is still free to use on a real post.
* `dry_run` takes precedence over `skip_queue`. The preview always answers synchronously.

***

## Read the response

| Field            | What it tells you                                                                                                                       |
| :--------------- | :-------------------------------------------------------------------------------------------------------------------------------------- |
| `dry_run`        | Always `true`. This is a preview, not a recorded transaction.                                                                           |
| `would_apply`    | A real post of this payload would be accepted against balances as they stand now.                                                       |
| `status`         | Status the real transaction would carry (`APPLIED`, or `INFLIGHT` if you sent `inflight: true`). Omitted when `would_apply` is `false`. |
| `precise_amount` | Movement in minor units, returned as a string so nothing is rounded.                                                                    |
| `balances`       | Before (`current_*`) and after (`resulting_*`) for each participating balance.                                                          |

Amounts on the preview are minor-unit strings. Convert with the same `precision` you sent: `display_amount = precise_amount / precision`.

An `@indicator` that does not exist yet is projected against a zeroed stand-in and marked `virtual: true`. A real post would create that General Ledger balance. The dry run does not.

`notes` carries warnings that are not rejections, such as a currency mismatch or a `scheduled_for` date (the preview applies as if now).

***

## When the transaction would fail

If the transaction would be rejected, you still get HTTP `200`. Read `would_apply` and `rejection`, not the status code.

```json 200 Would not apply wrap theme={"system"}
{
  "dry_run": true,
  "would_apply": false,
  "rejection": {
    "code": "TXN_INSUFFICIENT_FUNDS",
    "reason": "insufficient_funds",
    "message": "insufficient funds in source balance"
  },
  "reference": "ref_card_settle_4821",
  "currency": "USD",
  "amount": 120,
  "precise_amount": "12000",
  "precision": 100,
  "balances": [
    {
      "balance_id": "bln_source-bal-001",
      "role": "source",
      "currency": "USD",
      "current_balance": "5000",
      "resulting_balance": "5000"
    },
    {
      "balance_id": "bln_dest-bal-001",
      "role": "destination",
      "currency": "USD",
      "current_balance": "0",
      "resulting_balance": "0"
    }
  ]
}
```

`rejection.code` is the same catalog code a real post would return, so existing handling for codes like `TXN_INSUFFICIENT_FUNDS` still works.

On rejection, `resulting_*` matches `current_*`. The failed apply is not shown as a partial movement, and `status` is omitted.

Some failures never become a preview. Request validation and a missing balance ID return the same HTTP error a real post returns (`400`, `404`). Those run before the dry-run branch.

***

## Bulk and split transactions

[Bulk create](/transactions/bulk-transactions) and [multiple sources or destinations](/transactions/multiple-sources) use the same dry-run pattern. `skip_queue` changes how the preview treats items in the batch:

* `true`: the result is **cumulative**. Later transactions use the resulting balance change from earlier processed transactions in the dry run.
* `false`: the result is **independent**. Each item is processed on its own. Balance changes from other items in the same request are not applied.

In this example `bln_source-bal-001` has 500.00 available. The batch sends 450.00 to `bln_dest-bal-001`, then 100.00 to `blnk_dest-bal-002`.

<Tabs>
  <Tab title="Cumulative">
    Set `skip_queue` to `true`. The first item leaves 50.00. The second item needs 100.00, so `would_apply` is `false`.

    <CodeGroup>
      ```bash cURL wrap expandable theme={"system"}
      curl -X POST "http://localhost:5001/transactions/bulk" \
        -H "X-blnk-key: <api-key>" \
        -H "Content-Type: application/json" \
        -d '{
          "dry_run": true,
          "skip_queue": true,
          "transactions": [
            {
              "precise_amount": 45000,
              "precision": 100,
              "reference": "ref_payout_450",
              "currency": "USD",
              "source": "bln_source-bal-001",
              "destination": "bln_dest-bal-001",
              "description": "First payout"
            },
            {
              "precise_amount": 10000,
              "precision": 100,
              "reference": "ref_payout_100",
              "currency": "USD",
              "source": "bln_source-bal-001",
              "destination": "blnk_dest-bal-002",
              "description": "Second payout"
            }
          ]
        }'
      ```
    </CodeGroup>

    ```json 200 OK wrap expandable theme={"system"}
    {
      "dry_run": true,
      "would_apply": false,
      "cumulative": true,
      "atomic": false,
      "results": [
        {
          "dry_run": true,
          "would_apply": true,
          "status": "APPLIED",
          "reference": "ref_payout_450",
          "currency": "USD",
          "amount": 450,
          "precise_amount": "45000",
          "precision": 100
        },
        {
          "dry_run": true,
          "would_apply": false,
          "rejection": {
            "code": "TXN_INSUFFICIENT_FUNDS",
            "reason": "insufficient_funds",
            "message": "insufficient funds in source balance"
          },
          "reference": "ref_payout_100",
          "currency": "USD",
          "amount": 100,
          "precise_amount": "10000",
          "precision": 100
        }
      ],
      "balances": [
        {
          "balance_id": "bln_source-bal-001",
          "role": "source",
          "currency": "USD",
          "current_balance": "50000",
          "current_available": "50000",
          "current_credit_balance": "50000",
          "current_debit_balance": "0",
          "current_inflight_debit_balance": "0",
          "current_inflight_credit_balance": "0",
          "resulting_balance": "5000",
          "resulting_available": "5000",
          "resulting_credit_balance": "50000",
          "resulting_debit_balance": "45000",
          "resulting_inflight_debit_balance": "0",
          "resulting_inflight_credit_balance": "0"
        },
        {
          "balance_id": "bln_dest-bal-001",
          "role": "destination",
          "currency": "USD",
          "current_balance": "0",
          "current_available": "0",
          "current_credit_balance": "0",
          "current_debit_balance": "0",
          "current_inflight_debit_balance": "0",
          "current_inflight_credit_balance": "0",
          "resulting_balance": "45000",
          "resulting_available": "45000",
          "resulting_credit_balance": "45000",
          "resulting_debit_balance": "0",
          "resulting_inflight_debit_balance": "0",
          "resulting_inflight_credit_balance": "0"
        },
        {
          "balance_id": "blnk_dest-bal-002",
          "role": "destination",
          "currency": "USD",
          "current_balance": "0",
          "current_available": "0",
          "current_credit_balance": "0",
          "current_debit_balance": "0",
          "current_inflight_debit_balance": "0",
          "current_inflight_credit_balance": "0",
          "resulting_balance": "0",
          "resulting_available": "0",
          "resulting_credit_balance": "0",
          "resulting_debit_balance": "0",
          "resulting_inflight_debit_balance": "0",
          "resulting_inflight_credit_balance": "0"
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Independent">
    Set `skip_queue` to `false`. Each item is checked against the current 500.00 on its own, so both pass.

    <CodeGroup>
      ```bash cURL wrap expandable theme={"system"}
      curl -X POST "http://localhost:5001/transactions/bulk" \
        -H "X-blnk-key: <api-key>" \
        -H "Content-Type: application/json" \
        -d '{
          "dry_run": true,
          "skip_queue": false,
          "transactions": [
            {
              "precise_amount": 45000,
              "precision": 100,
              "reference": "ref_payout_450",
              "currency": "USD",
              "source": "bln_source-bal-001",
              "destination": "bln_dest-bal-001",
              "description": "First payout"
            },
            {
              "precise_amount": 10000,
              "precision": 100,
              "reference": "ref_payout_100",
              "currency": "USD",
              "source": "bln_source-bal-001",
              "destination": "blnk_dest-bal-002",
              "description": "Second payout"
            }
          ]
        }'
      ```
    </CodeGroup>

    ```json 200 OK wrap expandable theme={"system"}
    {
      "dry_run": true,
      "would_apply": true,
      "cumulative": false,
      "atomic": false,
      "results": [
        {
          "dry_run": true,
          "would_apply": true,
          "status": "APPLIED",
          "reference": "ref_payout_450",
          "currency": "USD",
          "amount": 450,
          "precise_amount": "45000",
          "precision": 100,
          "balances": [
            {
              "balance_id": "bln_source-bal-001",
              "role": "source",
              "currency": "USD",
              "current_balance": "50000",
              "current_available": "50000",
              "current_credit_balance": "50000",
              "current_debit_balance": "0",
              "current_inflight_debit_balance": "0",
              "current_inflight_credit_balance": "0",
              "resulting_balance": "5000",
              "resulting_available": "5000",
              "resulting_credit_balance": "50000",
              "resulting_debit_balance": "45000",
              "resulting_inflight_debit_balance": "0",
              "resulting_inflight_credit_balance": "0"
            },
            {
              "balance_id": "bln_dest-bal-001",
              "role": "destination",
              "currency": "USD",
              "current_balance": "0",
              "current_available": "0",
              "current_credit_balance": "0",
              "current_debit_balance": "0",
              "current_inflight_debit_balance": "0",
              "current_inflight_credit_balance": "0",
              "resulting_balance": "45000",
              "resulting_available": "45000",
              "resulting_credit_balance": "45000",
              "resulting_debit_balance": "0",
              "resulting_inflight_debit_balance": "0",
              "resulting_inflight_credit_balance": "0"
            }
          ]
        },
        {
          "dry_run": true,
          "would_apply": true,
          "status": "APPLIED",
          "reference": "ref_payout_100",
          "currency": "USD",
          "amount": 100,
          "precise_amount": "10000",
          "precision": 100,
          "balances": [
            {
              "balance_id": "bln_source-bal-001",
              "role": "source",
              "currency": "USD",
              "current_balance": "50000",
              "current_available": "50000",
              "current_credit_balance": "50000",
              "current_debit_balance": "0",
              "current_inflight_debit_balance": "0",
              "current_inflight_credit_balance": "0",
              "resulting_balance": "40000",
              "resulting_available": "40000",
              "resulting_credit_balance": "50000",
              "resulting_debit_balance": "10000",
              "resulting_inflight_debit_balance": "0",
              "resulting_inflight_credit_balance": "0"
            },
            {
              "balance_id": "blnk_dest-bal-002",
              "role": "destination",
              "currency": "USD",
              "current_balance": "0",
              "current_available": "0",
              "current_credit_balance": "0",
              "current_debit_balance": "0",
              "current_inflight_debit_balance": "0",
              "current_inflight_credit_balance": "0",
              "resulting_balance": "10000",
              "resulting_available": "10000",
              "resulting_credit_balance": "10000",
              "resulting_debit_balance": "0",
              "resulting_inflight_debit_balance": "0",
              "resulting_inflight_credit_balance": "0"
            }
          ]
        }
      ],
      "notes": [
        "items are dispatched concurrently unless skip_queue is set, so each item is projected independently against current balances and real execution order is not guaranteed"
      ]
    }
    ```
  </Tab>
</Tabs>

***

## Need help?

We are very happy to help you make the most of Blnk, regardless of whether it is your first time or you are switching from another tool.

To ask questions or discuss issues, please [contact us](mailto:support@blnkfinance.com) or [join our Discord community](https://discord.gg/7WNv94zPpx).

<CtaCallout title="Connect your ledger to Blnk Cloud" href="https://cloud.blnkfinance.com/auth/sign-up?utm_source=blnk_docs&utm_medium=documentation&utm_campaign=need-help" buttonLabel="Open Blnk Cloud" trackingEvent="clicked_cloud_signup">
  Sign up and manage your ledger with our back-office dashboard. You can invite teammates to collaborate and manage your ledger operations directly from the dashboard.
</CtaCallout>

<RelatedTopics
  items={[
{ title: "Dry-run a transaction", href: "/reference/dry-run" },
{ title: "Transactions overview", href: "/transactions/introduction" },
{ title: "Bulk transactions", href: "/transactions/bulk-transactions" },
{ title: "Multiple sources", href: "/transactions/multiple-sources" },
{ title: "Create inflight", href: "/transactions/inflight/creating-inflight" },
]}
/>
