> ## 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 a transaction

> Preview a transaction without writing it 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>;
};

<Note>
  If you're using the auto-provisioned `Enterprise Core` instance included with your Production License deployment, set the base URL to: `https://ENTERPRISE_PUBLIC_URL/core`.

  If you're connecting to a different Core instance, use the publicly accessible base URL for that instance instead.
</Note>

### Authorization

If set, the API uses an API key for authentication. Include the following header in your requests: `X-blnk-key: <api-key>`.

Replace `<api-key>` with your secret API key. Ensure the key is kept secure and not exposed in public repositories or client-side code.

See also: [Scoped API keys](/api-keys/overview) and [Secure your Blnk server](/advanced/secure-blnk).

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

Send the same body as [Record a transaction](/reference/create-transaction) and set `dry_run` to `true`. Blnk returns a projection instead of a recorded transaction.

The preview always answers synchronously with HTTP `200`. `dry_run` takes precedence over `skip_queue`. A projected rejection is `200` with `would_apply: false`, not an HTTP error.

`dry_run` also works on [bulk create](/reference/bulk-transactions), [refund](/reference/refund-transaction), and [update inflight](/reference/update-inflight). See [Dry-run transactions](/transactions/dry-run).

### Body

<ParamField body="dry_run" type="boolean" required>
  Set `true` to project the transaction without writing anything. No transaction row, balance change, queue entry, webhook, or hook is created, and the `reference` is not consumed.
</ParamField>

<ParamField body="precise_amount" type="integer">
  The transaction amount in its smallest unit (recommended). Include the corresponding `precision` value. See [Precision](/transactions/precision).

  <Warning>
    Either `precise_amount` or `amount` should be provided, not both.
  </Warning>
</ParamField>

<ParamField body="amount" type="float">
  The transaction amount as a float. Blnk multiplies `amount` by `precision` to store `precise_amount`.
</ParamField>

<ParamField body="currency" type="string" required>
  The currency of the transaction amount.
</ParamField>

<ParamField body="precision" type="integer" default="1" required>
  Precision for the transaction's currency. See [Precision](/transactions/precision).
</ParamField>

<ParamField body="reference" type="string" required>
  Unique transaction reference. A dry run does not consume it.
</ParamField>

<ParamField body="source" type="string" required>
  Balance sending the amount. `@` prefix indicates an [internal balance](/balances/internal-balances).
</ParamField>

<ParamField body="destination" type="string" required>
  Balance receiving the amount. `@` prefix indicates an [internal balance](/balances/internal-balances).
</ParamField>

<ParamField body="description" type="string">
  Narration of the transaction.
</ParamField>

<ParamField body="allow_overdraft" type="boolean" default="false">
  Whether the source can go negative. See [Overdrafts](/transactions/overdrafts).
</ParamField>

<ParamField body="inflight" type="boolean" default="false">
  When `true`, the preview uses `INFLIGHT` status and projects inflight balances. See [Create inflight](/transactions/inflight/creating-inflight).
</ParamField>

<ParamField body="skip_queue" type="boolean" default="false">
  Ignored for a single-transaction dry run. The preview always answers now. For [bulk](/reference/bulk-transactions) and splits, this flag selects cumulative vs independent projection. See [Bulk and split transactions](/transactions/dry-run#bulk-and-split-transactions).
</ParamField>

<ParamField body="sources" type="array">
  Multiple sources instead of `source`. See [Multiple sources](/reference/multiple-sources).
</ParamField>

<ParamField body="destinations" type="array">
  Multiple destinations instead of `destination`. See [Multiple destinations](/reference/multiple-destinations).
</ParamField>

### Response

<ResponseField name="dry_run" type="boolean" required>
  Always `true`. This is a preview, not a recorded transaction.
</ResponseField>

<ResponseField name="would_apply" type="boolean" required>
  Whether a real post of this payload would be accepted against balances as they stand now.
</ResponseField>

<ResponseField name="rejection" type="object">
  Present when `would_apply` is `false`. `code` is the same catalog code a real post would return.

  <Expandable title="Rejection properties">
    <ResponseField name="code" type="string">
      Stable error code, such as `TXN_INSUFFICIENT_FUNDS` or `TXN_DUPLICATE_REFERENCE`. See [API error codes](/advanced/error-codes).
    </ResponseField>

    <ResponseField name="reason" type="string">
      Short category for the rejection.
    </ResponseField>

    <ResponseField name="message" type="string">
      Human-readable rejection message.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="status" type="string">
  Status the real transaction would carry (`APPLIED`, or `INFLIGHT` if you sent `inflight: true`). Omitted when `would_apply` is `false`.
</ResponseField>

<ResponseField name="reference" type="string">
  The reference you sent. It is still unused after a dry run.
</ResponseField>

<ResponseField name="currency" type="string">
  Currency of the projected movement.
</ResponseField>

<ResponseField name="amount" type="float">
  Display amount of the projected movement.
</ResponseField>

<ResponseField name="precise_amount" type="string">
  Movement in minor units, returned as a string so nothing is rounded.
</ResponseField>

<ResponseField name="precision" type="float">
  Precision used to convert `precise_amount`.
</ResponseField>

<ResponseField name="operation" type="string">
  Present on inflight previews only: `commit` or `void`.
</ResponseField>

<ResponseField name="balances" type="array" required>
  Before and after state for each participating balance. Amounts are minor-unit strings.

  <Expandable title="Balance projection">
    <ResponseField name="balance_id" type="string">
      Balance ID, or the `@indicator` when the balance is virtual.
    </ResponseField>

    <ResponseField name="role" type="string">
      `source` or `destination`.
    </ResponseField>

    <ResponseField name="currency" type="string">
      Currency of the balance.
    </ResponseField>

    <ResponseField name="virtual" type="boolean">
      `true` when the `@indicator` does not exist yet. The preview uses a zeroed stand-in and does not create the balance.
    </ResponseField>

    <ResponseField name="current_balance" type="string">
      Net balance before the projected movement.
    </ResponseField>

    <ResponseField name="current_available" type="string">
      Spendable funds before the movement (`balance` minus inflight and queued debits).
    </ResponseField>

    <ResponseField name="current_credit_balance" type="string">
      Credit balance before the movement.
    </ResponseField>

    <ResponseField name="current_debit_balance" type="string">
      Debit balance before the movement.
    </ResponseField>

    <ResponseField name="current_inflight_debit_balance" type="string">
      Inflight debit before the movement.
    </ResponseField>

    <ResponseField name="current_inflight_credit_balance" type="string">
      Inflight credit before the movement.
    </ResponseField>

    <ResponseField name="resulting_balance" type="string">
      Net balance after the projected movement. Matches `current_balance` when `would_apply` is `false`.
    </ResponseField>

    <ResponseField name="resulting_available" type="string">
      Spendable funds after the movement.
    </ResponseField>

    <ResponseField name="resulting_credit_balance" type="string">
      Credit balance after the movement.
    </ResponseField>

    <ResponseField name="resulting_debit_balance" type="string">
      Debit balance after the movement.
    </ResponseField>

    <ResponseField name="resulting_inflight_debit_balance" type="string">
      Inflight debit after the movement.
    </ResponseField>

    <ResponseField name="resulting_inflight_credit_balance" type="string">
      Inflight credit after the movement.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="legs" type="array">
  One entry per split that would apply on a multiple-source or multiple-destination transaction.

  <Expandable title="Leg projection">
    <ResponseField name="identifier" type="string">
      Source or destination balance for this leg.
    </ResponseField>

    <ResponseField name="role" type="string">
      `source` or `destination`.
    </ResponseField>

    <ResponseField name="precise_amount" type="string">
      Leg amount in minor units.
    </ResponseField>

    <ResponseField name="amount" type="float">
      Display amount for the leg.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="notes" type="array">
  Advisory messages that are not rejections, such as a currency mismatch or a `scheduled_for` date being ignored.
</ResponseField>

<RequestExample>
  ```bash 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"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 Dry Run 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"
      }
    ]
  }
  ```

  ```json 200 Dry Run Not Applied 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",
        "current_available": "5000",
        "current_credit_balance": "5000",
        "current_debit_balance": "0",
        "current_inflight_debit_balance": "0",
        "current_inflight_credit_balance": "0",
        "resulting_balance": "5000",
        "resulting_available": "5000",
        "resulting_credit_balance": "5000",
        "resulting_debit_balance": "0",
        "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": "0",
        "resulting_available": "0",
        "resulting_credit_balance": "0",
        "resulting_debit_balance": "0",
        "resulting_inflight_debit_balance": "0",
        "resulting_inflight_credit_balance": "0"
      }
    ]
  }
  ```

  ```json 400 theme={"system"}
  {
    "errors": "amount: either amount or precise_amount is required.",
    "error_detail": {
      "code": "TXN_VALIDATION_ERROR",
      "message": "amount: either amount or precise_amount is required."
    }
  }
  ```

  ```json 404 theme={"system"}
  {
    "error": "Balance with ID 'bln_00000000-0000-0000-0000-000000000000' not found",
    "error_detail": {
      "code": "TXN_NOT_FOUND",
      "message": "Balance with ID 'bln_00000000-0000-0000-0000-000000000000' not found",
      "details": {}
    }
  }
  ```
</ResponseExample>

## 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 transactions", href: "/transactions/dry-run" },
{ title: "Record a transaction", href: "/reference/create-transaction" },
{ title: "Bulk transactions", href: "/reference/bulk-transactions" },
{ title: "API error codes", href: "/advanced/error-codes" },
]}
/>
