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

# Set up in Grok Bot

> Ask your Grok Bot to add LedgerSync, sign in, and ask your first question.

export const AiStuck = () => <div className="lsai-stuck">
    Stuck? <a href="https://ledgersync.com/book-a-demo" target="_blank" rel="noopener noreferrer">Book a call with
    our team</a> and we'll help you, or email{" "}
    <a href="mailto:support@ledgersync.com">support@ledgersync.com</a> with the step and what the screen says.
    Never send passwords or card numbers.
  </div>;

export const AiNote = ({tone, children}) => <div className={"lsai-note lsai-note-" + (tone || "gray")}>{children}</div>;

export const AiCopy = ({label, text}) => {
  const [copied, setCopied] = useState(false);
  const copy = () => {
    if (navigator.clipboard) {
      navigator.clipboard.writeText(text).then(() => {
        setCopied(true);
        setTimeout(() => setCopied(false), 1600);
      }).catch(() => {});
    }
  };
  return <div className="lsai-copy">
      {label && <div className="lsai-copy-label">{label}</div>}
      <div className="lsai-copy-row">
        <code className="lsai-copy-text">{text}</code>
        <button type="button" className="lsai-copy-button" onClick={copy}>{copied ? "Copied" : "Copy"}</button>
      </div>
    </div>;
};

export const AiStep = ({id, n, total, label, title, img, caption, imgs, stage, children}) => {
  const [open, setOpen] = useState(null);
  const closeRef = useRef(null);
  const openerRef = useRef(null);
  useEffect(() => {
    if (!open) return undefined;
    const root = document.documentElement;
    const overflow = root.style.overflow;
    root.style.overflow = "hidden";
    if (closeRef.current) closeRef.current.focus({
      preventScroll: true
    });
    return () => {
      root.style.overflow = overflow;
      if (openerRef.current) openerRef.current.focus({
        preventScroll: true
      });
    };
  }, [open]);
  const pictures = imgs || (img ? [{
    src: img,
    caption
  }] : []);
  return <div className="lsai-step" id={id} data-stage={stage}>
      <div className="lsai-step-num" aria-hidden="true">{n}</div>
      <div className="lsai-step-main">
        <div className="lsai-step-label">{label || "Step " + n + " of " + total}</div>
        <div className="lsai-step-title">{title}</div>
        <div className="lsai-step-text">{children}</div>
      </div>
      {pictures.length > 0 && <div className="lsai-thumbs">
          {pictures.map(pic => <a key={pic.src} className="lsai-thumb" href={pic.src} title="Click to see it larger" onClick={e => {
    e.preventDefault();
    openerRef.current = e.currentTarget;
    setOpen(pic);
  }}>
              <img src={pic.src} alt="" loading="lazy" />
              <span className="lsai-thumb-caption">{pic.caption ? pic.caption + " · " : ""}click to enlarge</span>
            </a>)}
        </div>}
      {open && <div className="lsai-lightbox" role="dialog" aria-modal="true" aria-label={open.caption || title} onClick={e => {
    if (e.detail < 2) setOpen(null);
  }} onKeyDown={e => {
    if (e.key === "Escape") setOpen(null);
    if (e.key === "Tab") e.preventDefault();
  }}>
          <button ref={closeRef} type="button" className="lsai-lightbox-close" onClick={() => setOpen(null)}>Close</button>
          <img src={open.src} alt={open.caption || title} />
          <span className="lsai-lightbox-note">{open.caption ? open.caption + " · " : ""}Click anywhere to close</span>
        </div>}
    </div>;
};

export const AiPage = ({title, subtitle, video, poster, stage, children}) => {
  const [playing, setPlaying] = useState(false);
  const [current, setCurrent] = useState(stage);
  const pageRef = useRef(null);
  const markRef = useRef(null);
  const topRef = useRef(null);
  const watchRef = useRef(null);
  const closeRef = useRef(null);
  useEffect(() => {
    if (!stage || !topRef.current || !pageRef.current) return undefined;
    const page = pageRef.current;
    const top = topRef.current;
    let frame = 0;
    const update = () => {
      frame = 0;
      const css = getComputedStyle(top);
      const stuck = css.position === "sticky" && markRef.current.getBoundingClientRect().top < (parseFloat(css.top) || 0);
      if (stuck !== top.classList.contains("lsai-top-stuck")) {
        const root = document.documentElement;
        root.style.overflowAnchor = "none";
        requestAnimationFrame(() => requestAnimationFrame(() => {
          root.style.overflowAnchor = "";
        }));
        if (stuck) {
          const before = top.offsetHeight;
          const margin = parseFloat(css.marginBottom) || 0;
          top.style.marginBottom = margin + before + "px";
          top.classList.add("lsai-top-stuck");
          top.style.marginBottom = margin + before - top.offsetHeight + "px";
        } else {
          top.classList.remove("lsai-top-stuck");
          top.style.marginBottom = "";
        }
      }
      const atEnd = window.innerHeight + window.scrollY >= document.documentElement.scrollHeight - 8;
      const line = atEnd ? Infinity : top.getBoundingClientRect().bottom + 120;
      if (stuck) {
        const height = top.offsetHeight + "px";
        if (document.documentElement.style.getPropertyValue("--lsai-pinned-h") !== height) {
          document.documentElement.style.setProperty("--lsai-pinned-h", height);
        }
      }
      let next = stage;
      page.querySelectorAll("[data-stage]").forEach(el => {
        if (el.getBoundingClientRect().top < line) next = Number(el.getAttribute("data-stage"));
      });
      setCurrent(next);
    };
    const schedule = () => {
      if (!frame) frame = requestAnimationFrame(update);
    };
    const reset = () => {
      top.classList.remove("lsai-top-stuck");
      top.style.marginBottom = "";
      schedule();
    };
    const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(schedule);
    if (observer) {
      observer.observe(top, {
        box: "border-box"
      });
      observer.observe(page);
    }
    window.addEventListener("scroll", schedule, {
      passive: true
    });
    window.addEventListener("resize", reset);
    update();
    return () => {
      document.documentElement.style.removeProperty("--lsai-pinned-h");
      if (observer) observer.disconnect();
      window.removeEventListener("scroll", schedule);
      window.removeEventListener("resize", reset);
      if (frame) cancelAnimationFrame(frame);
    };
  }, [stage, title]);
  useEffect(() => {
    if (!playing) return undefined;
    const root = document.documentElement;
    const overflow = root.style.overflow;
    root.style.overflow = "hidden";
    if (closeRef.current) closeRef.current.focus({
      preventScroll: true
    });
    return () => {
      root.style.overflow = overflow;
      if (watchRef.current) watchRef.current.focus({
        preventScroll: true
      });
    };
  }, [playing]);
  const stages = ["Get ready", "Add it to your AI", "Sign in", "Click Allow", "Ask a question"];
  return <div ref={pageRef} className={stage ? "lsai-page lsai-page-pinned" : "lsai-page"}>
      <div ref={markRef} className="lsai-top-mark" aria-hidden="true" />
      <div ref={topRef} className="lsai-top">
        <div className="lsai-head">
          <div className="lsai-head-text">
            <h1 className="lsai-title">{title}</h1>
            {subtitle && <p className="lsai-subtitle">{subtitle}</p>}
          </div>
          {video && <button ref={watchRef} type="button" className="lsai-video-button" onClick={() => setPlaying(true)}>
              <span className="lsai-video-play" aria-hidden="true">▶</span>
              <span className="lsai-video-label"><strong>Watch it first</strong><span>Short setup video</span></span>
            </button>}
        </div>
        {stage && <div className="lsai-progress-wrap">
            <ol className="lsai-progress" aria-label="Setup progress">
              {stages.map((label, i) => {
    const n = i + 1;
    const state = n < current ? "lsai-done" : n === current ? "lsai-current" : "lsai-todo";
    return <li key={label} className={"lsai-progress-item " + state} aria-current={n === current ? "step" : undefined}>
                    <span className="lsai-progress-bar" />
                    <span className="lsai-progress-label">{label}</span>
                  </li>;
  })}
            </ol>
            <div className="lsai-progress-now">{stages[current - 1]}</div>
          </div>}
      </div>
      {playing && <div className="lsai-lightbox lsai-video-box" role="dialog" aria-modal="true" aria-label={title + ": setup video"} tabIndex={-1} onClick={e => {
    if (e.target === e.currentTarget) setPlaying(false);
  }} onKeyDown={e => {
    if (e.key === "Escape") setPlaying(false);
    if (e.key === "Tab") {
      e.preventDefault();
      const close = e.currentTarget.querySelector("button");
      (document.activeElement === close ? e.currentTarget.querySelector("video") : close).focus({
        preventScroll: true
      });
    }
  }}>
          <button ref={closeRef} type="button" className="lsai-lightbox-close" onClick={() => setPlaying(false)}>Close</button>
          <video className="lsai-video-player" controls autoPlay playsInline tabIndex={0} poster={poster} src={video} />
          <span className="lsai-lightbox-note">Click Close when you are done</span>
        </div>}
      {children}
    </div>;
};

<AiPage title="Set up in Grok Bot" subtitle="4 steps · about 2 minutes · in your Grok Bot chat" stage={2}>
  Grok Bot is Grok's agent with its own computer. You add LedgerSync by asking your bot. Using Grok on grok.com
  instead? Go to [Set up in Grok](/ai/setup-grok).

  <AiStep id="add" stage={2} n={1} total={4} title="Ask your bot to add LedgerSync">
    1. Click **Copy** below.
    2. In your Grok Bot chat, click the message box. Press **Ctrl+V** (Windows) or **Command+V** (Mac), then press
       **Enter**.

    <AiCopy label="Your message to Grok Bot" text="Add a custom remote MCP server named LedgerSync with URL https://api.ledgersyncappv2.com/mcp" />

    Your bot adds LedgerSync and shows a card to sign in. Have your LedgerSync login ready.
  </AiStep>

  <AiStep id="sign-in" stage={3} n={2} total={4} title="Sign in with your LedgerSync login">
    Use the card your bot shows to sign in.

    1. Type the email or username you use in the LedgerSync app. Click **Next**.
    2. Type your password. Click **Sign in**.
    3. Asked for a code? Type the one from your Google Authenticator app, then click **Verify**.

    <AiNote tone="yellow">
      **The page says Create your LedgerSync account?** No LedgerSync login uses that email. Click **Change** and type
      your LedgerSync username. Don't create a second account. Your firm has no LedgerSync account yet? Sign up at
      [ledgersyncappv2.com/sign-up](https://ledgersyncappv2.com/sign-up) first, then come back here.
    </AiNote>
  </AiStep>

  <AiStep id="allow" stage={4} n={3} total={4} title="Click Allow, then Allow access">
    You see your firm's name. Click **Allow**.

    Next you see **Cursor would like access to your account**. That's normal: Grok Bot signs in through Cursor.
    Click **Allow access**. You only see this the first time.
  </AiStep>

  <AiStep id="test" stage={5} n={4} total={4} title="Ask your first question">
    Click **Copy** below. Paste it in your Grok Bot chat, then press **Enter**.

    <AiCopy label="Your test question" text="Use LedgerSync to check whether my account is ready." />

    * Your bot says your LedgerSync account is ready: you're done.
    * Anything else: see [Troubleshooting](/ai/troubleshooting).

    <AiNote tone="yellow">
      **Grok Bot may change things in LedgerSync without asking you first.** Tell it exactly what you want. Before it
      sends a message to a client, ask it to show you the message first.
    </AiNote>
  </AiStep>

  <Accordion title="What to ask next">
    <Tip>
      Your clients from the LedgerSync app are already here. Acme is an example: use your client's name.
    </Tip>

    ### Add a client and connect their bank

    <Steps>
      <Step title="Add your client">
        Ask: "Add my client Acme, [acme@example.com](mailto:acme@example.com)."
      </Step>

      <Step title="Connect their bank">
        Ask: "Send Acme a link to connect their bank." Open the link, pick your client's bank on the LedgerSync
        page, and choose what to connect: transactions, statements, checks. Then sign in with their bank login on
        the secure page that opens: LedgerSync's own, or our bank-data partner's for some banks. Some banks need
        one sign-in for each connection. Never in the chat.

        Don't have their bank login? Ask: "Email Acme an invitation to connect their bank." LedgerSync emails them
        a link that signs them in to their LedgerSync account, where they connect the bank themselves. The
        invitation's link works for 6 days, the link above for 3.
      </Step>

      <Step title="Ask about their bank">
        When the bank is connected, ask: "Show Acme's bank balances."
      </Step>
    </Steps>

    ### More things to ask

    <CardGroup cols={2}>
      <Card title="Is a bank supported?" icon="building-columns">
        "Does LedgerSync work with First National Bank?"
      </Card>

      <Card title="Find a client" icon="magnifying-glass">
        "Find my client Acme."
      </Card>

      <Card title="Balances" icon="wallet">
        "Show Acme's bank balances."
      </Card>

      <Card title="Transactions" icon="list">
        "Show last month's transactions for Acme's checking account."
      </Card>

      <Card title="Statements" icon="file-pdf">
        "Get Acme's September bank statement."
      </Card>

      <Card title="Problems" icon="triangle-exclamation">
        "Which of my clients' banks are not working?"
      </Card>

      <Card title="Message clients" icon="envelope">
        "Email every client with a broken American Express connection a link to reconnect it."
      </Card>

      <Card title="Invite a new client to connect their bank" icon="user-plus">
        "Add my new client Acme, [acme@example.com](mailto:acme@example.com), and email them an invitation to connect their bank."
      </Card>

      <Card title="Connect a bank" icon="link">
        "Send Acme a link to connect their bank."
      </Card>

      <Card title="Check images" icon="money-check">
        "Send Acme a link to connect their bank's check images."
      </Card>

      <Card title="Convert a statement PDF" icon="file-arrow-up" href="/ai/convert-statement">
        "Convert a bank statement PDF into transactions."
      </Card>
    </CardGroup>

    Check images arrive in the LedgerSync app, not in the chat. On a check images link, Checks comes already ticked:
    tick Transactions or Statements too to connect them in the same visit.

    <Tip>
      Claude and ChatGPT ask you before they change something. Allow it if it looks right. Grok may change things
      without asking, so tell it exactly what you want.
    </Tip>

    A bank needs the LedgerSync desktop app? The AI tells you when a refresh needs it. See
    [Banks that need the desktop app](/ai/desktop-app).
  </Accordion>

  <AiStuck />
</AiPage>


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