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

# DualEntry Docs

> Guides, API reference, CLI, and MCP server documentation for DualEntry, the AI-native ERP for accountants, controllers, and finance teams.

export const CliShowcase = ({children}) => {
  const cliTabs = [{
    "id": "install",
    "label": "Install and sign in",
    "blurb": "Install with Homebrew, then sign in through your browser.",
    "link": {
      "href": "/developers/guides/cli/quickstart",
      "text": "Read the CLI quickstart"
    },
    "steps": [{
      "cmd": "brew install dualentry/tap/dualentry",
      "out": ["==> Tapping dualentry/tap", "==> Installing dualentry from dualentry/tap", "🍺  /opt/homebrew/Cellar/dualentry/0.1.18"]
    }, {
      "cmd": "dualentry auth login",
      "out": ["Opening browser for login...", "Logged in as you@example.com (org 4821)."]
    }, {
      "cmd": "dualentry auth status",
      "out": ["API URL: https://api.dualentry.com", "User: you@example.com", "Organization: 4821", "Authenticated via API key", "", "/$$$$$$$                      /$$                       /$$", "| $$__  $$                    | $$                      | $$", "| $$  \\ $$ /$$   /$$  /$$$$$$ | $$  /$$$$$$  /$$$$$$$  /$$$$$$    /$$$$$$  /$$   /$$", "| $$  | $$| $$  | $$ |____  $$| $$ /$$__  $$| $$__  $$|_  $$_/   /$$__  $$| $$  | $$", "| $$  | $$| $$  | $$  /$$$$$$$| $$| $$$$$$$$| $$  \\ $$  | $$    | $$  \\__/| $$  | $$", "| $$  | $$| $$  | $$ /$$__  $$| $$| $$_____/| $$  | $$  | $$ /$$| $$      | $$  | $$", "| $$$$$$$/|  $$$$$$/|  $$$$$$$| $$|  $$$$$$$| $$  | $$  |  $$$$/| $$      |  $$$$$$$", "|_______/  \\______/  \\_______/|__/ \\_______/|__/  |__/   \\___/  |__/       \\____  $$", "                                                                           /$$  | $$", "                                                                          |  $$$$$$/", "                                                                           \\______/"]
    }]
  }, {
    "id": "invoices",
    "label": "Review invoices",
    "blurb": "Pull up an invoice and see what the customer still owes.",
    "link": {
      "href": "/developers/guides/cli/how-to-review-outstanding-invoices",
      "text": "How to review outstanding invoices"
    },
    "steps": [{
      "cmd": "dualentry invoices get 1043",
      "out": ["╭──────────────────────────╮", "│ INVOICE  IN-5834  POSTED │", "╰──────────────────────────╯", "Company: Acme Corp                Customer: Sprocket Inc.", "", "Number:           1043", "Date:             2026-09-08", "Due Date:         2026-10-08", "Terms:            Net 30", "Currency:         USD", "", "                                       Line Items", "┏━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓", "┃    # ┃ Description                    ┃        Qty ┃           Rate ┃         Amount ┃", "┡━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩", "│    1 │ Implementation services        │          1 │      $2,400.00 │      $2,400.00 │", "├──────┼────────────────────────────────┼────────────┼────────────────┼────────────────┤", "│    2 │ Support hours                  │          8 │        $100.00 │        $800.00 │", "└──────┴────────────────────────────────┴────────────┴────────────────┴────────────────┘", "", "                                                  Total:       $3,200.00", "                                                   Paid:      -$1,200.00", "                                          ──────────────  ──────────────", "                                             Amount Due:       $2,000.00"]
    }]
  }, {
    "id": "month-end",
    "label": "Month-end journal entries",
    "blurb": "Pull every journal entry booked in a period for close review.",
    "link": {
      "href": "/developers/guides/cli/how-to-run-a-month-end-journal-entry-review",
      "text": "How to run a month-end journal entry review"
    },
    "steps": [{
      "cmd": "dualentry journal-entries list --start-date 2026-09-01 --end-date 2026-09-30 --limit 4",
      "out": ["                                       Journal Entries", "┏━━━━━━━━━┳━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━┓", "┃      ID ┃  # ┃    Date    ┃ Company   ┃ Memo             ┃ Currency ┃     Amount ┃ Status ┃", "┡━━━━━━━━━╇━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━┩", "│ JE-3310 │ 88 │ 2026-09-30 │ Acme Corp │ Payroll accrual  │   USD    │ $48,200.00 │ posted │", "│ JE-3311 │ 89 │ 2026-09-30 │ Acme Corp │ Rent accrual     │   USD    │  $1,250.00 │ posted │", "│ JE-3312 │ 90 │ 2026-09-30 │ Acme Corp │ Depreciation     │   USD    │  $6,875.00 │ posted │", "│ JE-3315 │ 91 │ 2026-09-30 │ Acme Corp │ FX revaluation   │   USD    │    $412.37 │ draft  │", "└─────────┴────┴────────────┴───────────┴──────────────────┴──────────┴────────────┴────────┘", "", "Showing 4 of 52"]
    }]
  }, {
    "id": "ci",
    "label": "Bill status in CI/CD",
    "blurb": "Authenticate with an API key and check bills from a scheduled job.",
    "link": {
      "href": "/developers/guides/cli/how-to-automate-bill-status-checks-in-cicd",
      "text": "How to automate bill status checks in CI/CD"
    },
    "steps": [{
      "cmd": "export X_API_KEY=\"$DUALENTRY_API_KEY\"",
      "out": []
    }, {
      "cmd": "dualentry auth status",
      "out": ["Authenticated via X_API_KEY environment variable"]
    }, {
      "cmd": "dualentry bills list --status posted --format json | jq '.count'",
      "out": ["14"]
    }]
  }, {
    "id": "bank-match",
    "label": "Bank matching",
    "blurb": "See where your bank-feed rows are in the matching pipeline.",
    "link": {
      "href": "/developers/guides/cli/reference#bank-matching",
      "text": "Bank matching commands in the reference"
    },
    "steps": [{
      "cmd": "dualentry bank-match status-counts",
      "out": ["┌─────────────────────────┬──────┐", "│ unprocessed             │ 0    │", "│ awaiting_setup          │ 0    │", "│ deterministic_suggested │ 126  │", "│ awaiting_ai             │ 0    │", "│ ai_in_progress          │ 0    │", "│ ai_suggested            │ 38   │", "│ ai_no_match             │ 4    │", "│ no_match                │ 2    │", "│ excluded                │ 11   │", "│ matched                 │ 1482 │", "└─────────────────────────┴──────┘"]
    }]
  }, {
    "id": "json",
    "label": "Script with JSON",
    "blurb": "Switch any command to JSON and pipe it into jq or your own scripts.",
    "link": {
      "href": "/developers/guides/cli/reference#list-records",
      "text": "Listing records as JSON in the reference"
    },
    "steps": [{
      "cmd": "dualentry invoices list --status posted --format json | jq -c '.items[] | {number, customer: .customer_name, amount_due}'",
      "out": ["{\"number\":1042,\"customer\":\"Widget Co.\",\"amount_due\":\"1500.00\"}", "{\"number\":1043,\"customer\":\"Sprocket Inc.\",\"amount_due\":\"2000.00\"}", "{\"number\":1044,\"customer\":\"Gearworks LLC\",\"amount_due\":\"860.50\"}", "{\"number\":1045,\"customer\":\"Widget Co.\",\"amount_due\":\"4125.00\"}"]
    }]
  }];
  const QUOTE_CHARS = ["\u0027", "\u0022", "$"];
  const [active, setActive] = useState(0);
  const [tick, setTick] = useState(0);
  const [replay, setReplay] = useState(0);
  const tab = cliTabs[active];
  const segments = [];
  tab.steps.forEach(step => {
    for (let i = 0; i < step.cmd.length; i++) segments.push("type");
    segments.push("enter");
    step.out.forEach(() => segments.push("line"));
  });
  const total = segments.length;
  useEffect(() => {
    setTick(0);
    const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (reduced) {
      setTick(total);
      return;
    }
    let t = 0;
    let timer;
    const delays = {
      type: 14,
      enter: 380,
      line: 45
    };
    const run = () => {
      t += 1;
      setTick(t);
      if (t < total) timer = setTimeout(run, delays[segments[t]] || 14);
    };
    timer = setTimeout(run, 250);
    return () => clearTimeout(timer);
  }, [active, replay]);
  const onKeyDown = e => {
    const keys = {
      ArrowDown: 1,
      ArrowRight: 1,
      ArrowUp: -1,
      ArrowLeft: -1
    };
    const move = keys[e.key] || 0;
    if (move === 0) return;
    e.preventDefault();
    const next = (active + move + cliTabs.length) % cliTabs.length;
    setActive(next);
    const nextTab = document.getElementById(`cli-tab-${cliTabs[next].id}`);
    if (nextTab) nextTab.focus();
  };
  const colorCmd = cmd => cmd.split(/(\s+)/).map((part, i) => {
    let cls = "home-tok-arg";
    if (i === 0 || (/^(dualentry|jq|brew|export)$/).test(part)) cls = "home-tok-cmd"; else if ((/^-/).test(part)) cls = "home-tok-flag"; else if (QUOTE_CHARS.includes(part[0]) || QUOTE_CHARS.includes(part[part.length - 1])) cls = "home-tok-str"; else if (part === "|") cls = "home-tok-prompt";
    return <span key={i} className={cls}>{part}</span>;
  });
  const colorOut = line => line.split(/(\bposted\b|\bPOSTED\b|\bdraft\b|==>)/).map((part, i) => {
    const cls = ({
      posted: "home-out-green",
      POSTED: "home-out-green",
      draft: "home-out-yellow",
      "==>": "home-out-blue"
    })[part];
    return cls ? <span key={i} className={cls}>{part}</span> : part;
  });
  const rendered = [];
  let left = tick;
  let typing = false;
  for (let s = 0; s < tab.steps.length && left > 0; s++) {
    const step = tab.steps[s];
    const typed = Math.min(left, step.cmd.length);
    left -= typed;
    typing = typed < step.cmd.length || left === 0;
    rendered.push(<div key={`c${s}`} className="home-term-line home-term-cmd">
        <span className="home-tok-prompt">$ </span>
        {colorCmd(step.cmd.slice(0, typed))}
        {typing && <span className="home-term-caret" />}
      </div>);
    if (left > 0) {
      left -= 1;
      const lines = Math.min(left, step.out.length);
      left -= lines;
      step.out.slice(0, lines).forEach((line, i) => rendered.push(<div key={`o${s}-${i}`} className="home-term-line">{colorOut(line)}{"\u00a0"}</div>));
    }
  }
  const finished = tick >= total;
  return <div className="home-cli">
      <div className="home-cli-intro">
        {children}
        <div className="home-cli-tabs" role="tablist" aria-orientation="vertical" aria-label="CLI workflows" onKeyDown={onKeyDown}>
          {cliTabs.map((t, i) => <button key={t.id} id={`cli-tab-${t.id}`} type="button" role="tab" aria-selected={i === active} aria-controls="cli-panel" tabIndex={i === active ? 0 : -1} className="home-cli-tab" onClick={() => i === active ? setReplay(r => r + 1) : setActive(i)}>
              <span className="home-cli-tab-label">{t.label}</span>
              <span className="home-cli-tab-blurb">{t.blurb}</span>
            </button>)}
        </div>
      </div>
      <div className="home-cli-panel" id="cli-panel" role="tabpanel" aria-labelledby={`cli-tab-${tab.id}`}>
        <div className="home-terminal home-terminal-live">
          <div className="home-terminal-dots" aria-hidden="true"><span /><span /><span /></div>
          <div className="home-term-body" aria-hidden="true">
            {rendered}
            {finished && <div className="home-term-line">
                <span className="home-tok-prompt">$ </span>
                <span className="home-term-caret" />
              </div>}
          </div>
          <pre className="sr-only">{tab.steps.map(st => `$ ${st.cmd}\n${st.out.join("\n")}`).join("\n")}</pre>
        </div>
      </div>
      <a href={tab.link.href} className="home-cli-link">{tab.link.text} →</a>
    </div>;
};

export const CardStack = ({src, width, x, y, step, layers, border}) => <div className="home-card-art" aria-hidden="true">
    {layers.map((opacity, i) => <img key={i} src={src} alt="" className="home-card-art-layer home-card-art-shadow" style={{
  opacity,
  width,
  left: `${x}px`,
  top: `${y + (layers.length - i) * step}px`
}} />)}
    <img src={src} alt="" className="home-card-art-layer home-card-art-top" style={{
  width,
  left: `${x}px`,
  top: `${y}px`,
  border: border ? `1px solid ${border}` : "none"
}} />
  </div>;

export const AssistantButton = () => {
  const openAssistant = () => {
    const mac = (/Mac|iPhone|iPad/).test(navigator.platform);
    document.dispatchEvent(new KeyboardEvent("keydown", {
      key: "i",
      code: "KeyI",
      metaKey: mac,
      ctrlKey: !mac,
      bubbles: true
    }));
  };
  return <button type="button" className="home-assistant" onClick={openAssistant}>
      <span className="home-assistant-label">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round" aria-hidden="true">
          <path d="M12 3l1.9 5.6L19.5 10.5l-5.6 1.9L12 18l-1.9-5.6L4.5 10.5l5.6-1.9L12 3z" />
          <path d="M19 15l.8 2.2L22 18l-2.2.8L19 21l-.8-2.2L16 18l2.2-.8L19 15z" />
        </svg>
        Ask the Docs Assistant
      </span>
      <kbd className="home-assistant-kbd">Ctrl + I</kbd>
    </button>;
};

export const AppIconPanel = () => {
  const appAreas = [{
    icon: "dashboard",
    label: "Dashboard",
    href: "/accountants/reporting-analytics/dashboards"
  }, {
    icon: "anomaly-detection",
    label: "Anomaly Detection",
    href: "/accountants/ai-automation/anomaly-detection"
  }, {
    icon: "inbox",
    label: "Inbox",
    href: "/accountants/get-started/key-concepts#the-inbox",
    dot: true
  }, {
    icon: "accounting-intelligence",
    label: "Accounting Intelligence",
    href: "/accountants/ai-automation/accounting-intelligence"
  }, {
    icon: "transactions",
    label: "Transactions",
    href: "/accountants/core-financials/general-ledger/journal-entries"
  }, {
    icon: "money-in",
    label: "Money In",
    href: "/accountants/core-financials/accounts-receivable"
  }, {
    icon: "money-out",
    label: "Money Out",
    href: "/accountants/core-financials/accounts-payable"
  }, {
    icon: "workflows",
    label: "Workflows",
    href: "/accountants/integrations/automation-and-developer-tools/bulk-import"
  }, {
    icon: "allocations",
    label: "Allocation",
    href: "/accountants/core-financials/general-ledger/allocation-journals"
  }, {
    icon: "fixed-assets",
    label: "Fixed Assets",
    href: "/accountants/core-financials/fixed-asset-management"
  }, {
    icon: "amortization",
    label: "Amortization",
    href: "/accountants/core-financials/prepaid-expense-amortization"
  }, {
    icon: "revenue-recognition",
    label: "Revenue Recognition",
    href: "/accountants/revenue-recognition"
  }, {
    icon: "recognition-timing",
    label: "Recognition Timing",
    href: "/accountants/revenue-recognition/recognition-timing"
  }, {
    icon: "close-checklist",
    label: "Close Checklist",
    href: "/accountants/core-financials/close-management/month-end-close-checklist"
  }, {
    icon: "close-workflows",
    label: "Close Management",
    href: "/accountants/core-financials/close-management"
  }, {
    icon: "flux-reporting",
    label: "Flux Reporting",
    href: "/accountants/reporting-analytics/flux-reporting"
  }, {
    icon: "report-center",
    label: "Report Center",
    href: "/accountants/reporting-analytics"
  }, {
    icon: "budgets",
    label: "Budgets",
    href: "/accountants/platform-configuration/budgeting-and-forecasting"
  }, {
    icon: "accounting-setup",
    label: "Accounting Setup",
    href: "/accountants/core-financials/general-ledger/chart-of-accounts"
  }, {
    icon: "tax-setup",
    label: "Tax Setup",
    href: "/accountants/core-financials/tax-management"
  }, {
    icon: "company",
    label: "Company",
    href: "/accountants/platform-configuration/multi-entity-consolidation"
  }];
  return <div className="home-icon-panel" role="navigation" aria-label="Browse docs by app area">
      {appAreas.map(({icon, label, href, dot}) => <a key={icon} href={href} className="home-icon-cell" aria-label={`${label}: open the docs for this area`}>
          <span className="home-icon" style={{
    maskImage: `url(/images/icons/${icon}.svg)`,
    WebkitMaskImage: `url(/images/icons/${icon}.svg)`
  }} />
          {dot && <span className="home-icon-dot" />}
          <span className="home-icon-tip" aria-hidden="true">
            <strong>{label}</strong>
            <span>Open the docs for this area</span>
          </span>
        </a>)}
    </div>;
};

<div className="home">
  <section className="home-hero">
    <img src="https://mintcdn.com/entryinc/ad8as-Q-RBSGqJJx/images/home/hero-texture.webp?fit=max&auto=format&n=ad8as-Q-RBSGqJJx&q=85&s=15f5a9013c7e8a4bf3fc502b3955368b" alt="" className="home-hero-texture" aria-hidden="true" width="1024" height="576" data-path="images/home/hero-texture.webp" />

    <div className="home-hero-body">
      <h1 className="home-hero-title">Welcome to DualEntry Docs</h1>
      <p className="home-hero-subtitle">What would you like to understand?</p>

      <AssistantButton />
    </div>
  </section>

  <section className="home-section home-paths">
    <a href="/accountants/get-started" className="home-path-card">
      <h2>DualEntry day to day</h2>
      <p>For accountants, controllers, and finance teams. Covers everything from setting up your chart of accounts to closing the books each month.</p>
      <span className="home-chip">Get started</span>

      <CardStack src="/images/home/card-accountants.webp" width={638} x={337} y={165} step={22} layers={[0.4, 0.4, 0.5, 0.7, 0.9]} border="#01242A" />
    </a>

    <a href="/developers/guides/api/quickstart" className="home-path-card">
      <h2>Build an app on our API</h2>
      <p>DualEntry gives you three ways to build on your organization’s accounting data: a RESTful API, a CLI, and an MCP server for AI assistants.</p>
      <span className="home-chip">Build your first company</span>

      <CardStack src="/images/home/card-api.webp" width={530} x={290} y={156} step={22} layers={[0.1, 0.4, 0.5, 0.6, 0.7]} />
    </a>

    <a href="/developers/guides/integrations-and-tools/mcp" className="home-path-card">
      <h2>Build on our MCP server</h2>
      <p>Build AI agents that securely work with your DualEntry data. From custom integrations to bespoke workflows, the /dualentry skill guides your AI tools.</p>
      <span className="home-chip">Connect the MCP server</span>

      <CardStack src="/images/home/card-mcp.webp" width={533} x={260} y={167} step={18} layers={[0.04, 0.2, 0.3, 0.4, 0.6, 0.74, 0.9]} border="rgba(155, 190, 196, 0.7)" />
    </a>
  </section>

  <section className="home-section home-split">
    <div className="home-prose">
      <h2>Tell us what you think</h2>
      <p>DualEntry gets better every time you tell us where it falls short, so don’t be polite. Tell us what you dislike, what you love, and what you wish existed. We read all of it, and we respond to all of it. For product feedback, email us at <a href="mailto:product-feedback@dualentry.com">{"product-feedback@dualentry.com"}</a>, and if you want to complain to a co-founder (or say nice things), you can email me at <a href="mailto:sn@dualentry.com">{"sn@dualentry.com"}</a>.</p>
      <p>This is the ERP we wished existed. We hope it earns a place in your day.</p>
    </div>

    <AppIconPanel />
  </section>

  <section className="home-section">
    <CliShowcase>
      <div className="home-prose">
        <h2>Accelerate development with the CLI</h2>
        <p>Install the DualEntry CLI, authenticate, and run your first command in under five minutes. For the full list of resources and flags, see the <a href="/developers/guides/cli/reference">Command Reference</a>. For end-to-end task guides, see <a href="/developers/guides/cli">Common Workflows</a>.</p>
      </div>
    </CliShowcase>
  </section>

  <section className="home-section home-split">
    <div className="home-prose">
      <h2>Report a bug or get help</h2>
      <p>When you report a bug, include what you were doing, what you expected, and what happened instead, along with the company and record involved if applicable. That context lets the team reproduce and fix the issue faster.</p>
    </div>

    <div className="home-help-cards">
      <a href="mailto:product-feedback@dualentry.com" className="home-help-card">
        <span className="home-help-icon" style={{ maskImage: "url(https://mintcdn.com/entryinc/ad8as-Q-RBSGqJJx/images/icons/bug.svg?fit=max&auto=format&n=ad8as-Q-RBSGqJJx&q=85&s=3e7669e7c9d3f388e66b6285630d554f)", WebkitMaskImage: "url(https://mintcdn.com/entryinc/ad8as-Q-RBSGqJJx/images/icons/bug.svg?fit=max&auto=format&n=ad8as-Q-RBSGqJJx&q=85&s=3e7669e7c9d3f388e66b6285630d554f)" }} />

        <h3>Bugs and product feedback</h3>
        <p>Email<br />{"product-feedback@dualentry.com"}</p>
      </a>

      <a href="mailto:ask@dualentry.com" className="home-help-card">
        <span className="home-help-icon" style={{ maskImage: "url(https://mintcdn.com/entryinc/ad8as-Q-RBSGqJJx/images/icons/help.svg?fit=max&auto=format&n=ad8as-Q-RBSGqJJx&q=85&s=215c0382b5d0befb81bd1aefb5cda4b9)", WebkitMaskImage: "url(https://mintcdn.com/entryinc/ad8as-Q-RBSGqJJx/images/icons/help.svg?fit=max&auto=format&n=ad8as-Q-RBSGqJJx&q=85&s=215c0382b5d0befb81bd1aefb5cda4b9)" }} />

        <h3>General support</h3>
        <p>Email<br />{"ask@dualentry.com"}</p>
      </a>
    </div>
  </section>

  <div className="home-footer" role="contentinfo">
    <a href="https://www.linkedin.com/company/dualentry/" aria-label="DualEntry on LinkedIn">
      <Icon icon="linkedin" iconType="brands" size={20} />
    </a>

    <a href="https://x.com/dualentry" aria-label="DualEntry on X">
      <Icon icon="x-twitter" iconType="brands" size={20} />
    </a>

    <a href="https://www.reddit.com/r/dualentry/" aria-label="DualEntry on Reddit">
      <Icon icon="reddit" iconType="brands" size={20} />
    </a>
  </div>
</div>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.