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

# Getting Started with Flinks Upload

> Enable Flinks Upload in Flinks Connect to process and extract data from bank statements.

export const FlinksVideo = ({videoId, playlist}) => {
  const PLAYLIST = [{
    id: '1183239584',
    hash: '5b5f7c9f89',
    title: 'Welcome to Flinks',
    page: '/'
  }, {
    id: '1183239766',
    hash: '4965a1d16c',
    title: 'Choosing your front-end integration',
    page: '/guides/connect/choose-a-frontend-solution'
  }, {
    id: '1183240266',
    hash: '17b592a0ac',
    title: 'Choosing your back-end integration',
    page: '/guides/connect/choose-a-backend-solution'
  }, {
    id: '1183240418',
    hash: 'a5adf4b7a4',
    title: 'Using the Flinks API and webhooks',
    page: '/guides/webhooks/introduction'
  }, {
    id: '1183240713',
    hash: 'a6fce4b746',
    title: 'Flinks Enrich Walkthrough',
    page: '/guides/enrich/getting-started'
  }, {
    id: '1183241038',
    hash: '869c6490df',
    title: 'Exploring Enrich attributes in the Dashboard',
    page: '/guides/dashboard/tools'
  }, {
    id: '1183241189',
    hash: 'b03e777aee',
    title: 'Flinks Upload Walkthrough',
    page: '/guides/upload/getting-started'
  }, {
    id: '1183241410',
    hash: '3a57b7e600',
    title: "You're live with Flinks",
    page: null
  }];
  const containerRef = useRef(null);
  const playerRef = useRef(null);
  const [ended, setEnded] = useState(false);
  const currentIndex = PLAYLIST.findIndex(v => v.id === videoId);
  const current = PLAYLIST[currentIndex];
  const next = currentIndex < PLAYLIST.length - 1 ? PLAYLIST[currentIndex + 1] : null;
  const shouldAutoplay = typeof window !== 'undefined' && new URLSearchParams(window.location.search).get('fv') === 'play';
  const linkTo = page => page ? `${page}?fv=play` : '#';
  useEffect(() => {
    setEnded(false);
    if (playerRef.current) {
      playerRef.current.off('ended');
      playerRef.current.off('play');
      playerRef.current = null;
    }
    let cancelled = false;
    let script = document.querySelector('script[src="https://player.vimeo.com/api/player.js"]');
    const init = () => {
      if (cancelled || !containerRef.current) return;
      const iframe = containerRef.current.querySelector('iframe');
      if (!iframe || typeof window.Vimeo === 'undefined') return;
      const player = new window.Vimeo.Player(iframe);
      playerRef.current = player;
      player.on('ended', () => {
        if (cancelled) return;
        if (playlist && next) {
          var allWraps = document.querySelectorAll('.fv-wrap');
          for (var i = 0; i < allWraps.length; i++) {
            var iframe = allWraps[i].querySelector('iframe');
            if (iframe && iframe.src.indexOf(next.id) !== -1) {
              allWraps[i].scrollIntoView({
                behavior: 'smooth',
                block: 'center'
              });
              var nextPlayer = new window.Vimeo.Player(iframe);
              setTimeout(function () {
                nextPlayer.play().catch(function () {});
              }, 600);
              break;
            }
          }
        } else {
          setEnded(true);
        }
      });
      player.on('play', () => {
        if (!cancelled) setEnded(false);
      });
      if (shouldAutoplay) {
        player.play().catch(() => {});
      }
    };
    if (!script) {
      script = document.createElement('script');
      script.src = 'https://player.vimeo.com/api/player.js';
      script.async = true;
      script.onload = init;
      document.head.appendChild(script);
    } else if (window.Vimeo) {
      setTimeout(init, 100);
    } else {
      script.addEventListener('load', init);
    }
    return () => {
      cancelled = true;
      if (playerRef.current) {
        playerRef.current.off('ended');
        playerRef.current.off('play');
        playerRef.current = null;
      }
    };
  }, [videoId]);
  const handleReplay = () => {
    if (playerRef.current) {
      playerRef.current.setCurrentTime(0);
      playerRef.current.play();
    }
    setEnded(false);
  };
  return <>
      <style>{`
        .fv-wrap {
          position: relative;
          width: 100%;
          border-radius: 16px;
          overflow: hidden;
        }
        .fv-aspect {
          padding: 56.25% 0 0 0;
          position: relative;
        }
        .fv-aspect iframe {
          position: absolute;
          top: 0; left: 0;
          width: 100%; height: 100%;
          border: 0;
        }

        /* --- overlay backdrop --- */
        .fv-overlay {
          position: absolute;
          inset: 0;
          z-index: 10;
          display: flex;
          align-items: center;
          justify-content: center;
          overflow-y: auto;
          padding: 16px;
          background: radial-gradient(ellipse at 50% 40%, rgba(0,10,20,0.80), rgba(0,0,0,0.92));
          backdrop-filter: blur(6px);
          -webkit-backdrop-filter: blur(6px);
          animation: fv-fade-in 0.35s ease-out;
        }
        .fv-overlay::-webkit-scrollbar { width: 0; }
        @keyframes fv-fade-in {
          from { opacity: 0; }
          to   { opacity: 1; }
        }

        /* --- glass card --- */
        .fv-card {
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 14px;
          padding: 28px 32px 24px;
          max-width: 380px;
          width: 100%;
          background: rgba(255,255,255,0.07);
          border: 1px solid rgba(255,255,255,0.10);
          border-radius: 32px 24px 28px 20px;
          box-shadow: 0 8px 40px rgba(0,0,0,0.25);
          animation: fv-card-up 0.4s ease-out both;
          animation-delay: 0.08s;
          margin: auto;
        }
        @keyframes fv-card-up {
          from { opacity: 0; transform: translateY(14px) scale(0.97); }
          to   { opacity: 1; transform: translateY(0) scale(1); }
        }

        /* --- text --- */
        .fv-label {
          font-family: var(--font-body, 'Helvetica Neue'), sans-serif;
          font-size: 11px !important;
          font-weight: 600;
          text-transform: uppercase;
          letter-spacing: 0.12em;
          color: rgba(0,172,228,0.85) !important;
          margin: 0;
        }
        .fv-title {
          font-family: var(--font-heading, 'Helvetica Neue'), sans-serif;
          font-size: 19px !important;
          font-weight: 600;
          line-height: 1.35;
          color: #fff !important;
          margin: 0;
          text-align: center;
        }
        .fv-counter {
          font-family: var(--font-body, 'Helvetica Neue'), sans-serif;
          font-size: 12px !important;
          color: rgba(255,255,255,0.35) !important;
          margin: 0;
        }

        /* --- pill buttons --- */
        .fv-actions {
          display: flex;
          gap: 10px;
          flex-wrap: wrap;
          justify-content: center;
          margin-top: 2px;
        }
        .fv-btn {
          display: inline-flex;
          align-items: center;
          gap: 6px;
          padding: 10px 26px;
          border-radius: 50px;
          font-family: var(--font-body, 'Helvetica Neue'), sans-serif;
          font-size: 14px !important;
          font-weight: 600;
          cursor: pointer;
          text-decoration: none !important;
          border: none;
          transition: transform 0.15s ease, box-shadow 0.15s ease;
        }
        .fv-btn:hover {
          transform: translateY(-1px);
        }
        .fv-btn:active {
          transform: translateY(0);
        }
        .fv-btn-primary {
          background: #fff;
          color: #0a0a0a !important;
          box-shadow: 0 2px 16px rgba(255,255,255,0.12);
        }
        .fv-btn-primary:hover {
          box-shadow: 0 4px 24px rgba(255,255,255,0.18);
        }
        .fv-btn-ghost {
          background: rgba(255,255,255,0.08);
          color: rgba(255,255,255,0.85) !important;
          border: 1px solid rgba(255,255,255,0.12);
        }
        .fv-btn-ghost:hover {
          background: rgba(255,255,255,0.13);
        }

        /* --- browse link --- */
        .fv-browse {
          font-family: var(--font-body, 'Helvetica Neue'), sans-serif;
          font-size: 12px !important;
          color: rgba(255,255,255,0.40) !important;
          text-decoration: none !important;
          transition: color 0.15s;
        }
        .fv-browse:hover {
          color: rgba(255,255,255,0.7) !important;
        }

        /* --- mobile --- */
        @media (max-width: 480px) {
          .fv-card {
            padding: 20px 16px 18px;
            gap: 10px;
            border-radius: 24px 18px 22px 16px;
          }
          .fv-title { font-size: 16px !important; }
          .fv-btn { font-size: 13px !important; padding: 9px 20px; }
        }
      `}</style>
      <div className="fv-wrap" ref={containerRef}>
        <div className="fv-aspect">
          <iframe src={`https://player.vimeo.com/video/${current.id}?h=${current.hash}&badge=0&autopause=0&player_id=0&app_id=58479`} allow="autoplay; fullscreen; picture-in-picture; clipboard-write" title={current.title} />
          {ended && <div className="fv-overlay">
              <div className="fv-card">
                {next ? <>
                    <p className="fv-label">Up next</p>
                    <p className="fv-title">{next.title}</p>
                    <p className="fv-counter">{currentIndex + 2} of {PLAYLIST.length}</p>
                    <div className="fv-actions">
                      <a href={linkTo(next.page)} className="fv-btn fv-btn-primary">
                        Continue →
                      </a>
                      <button onClick={handleReplay} className="fv-btn fv-btn-ghost">
                        Replay
                      </button>
                    </div>
                  </> : <>
                    <p className="fv-label">Series complete</p>
                    <p className="fv-title">Nice — you've watched them all</p>
                    <div className="fv-actions">
                      <button onClick={handleReplay} className="fv-btn fv-btn-primary">
                        Replay
                      </button>
                      <a href="/guides/getting-started/walkthrough-videos" className="fv-btn fv-btn-ghost">
                        All videos
                      </a>
                    </div>
                  </>}

                <a href="/guides/getting-started/walkthrough-videos" className="fv-browse">
                  Browse all videos
                </a>
              </div>
            </div>}
        </div>
      </div>
    </>;
};

<FlinksVideo videoId="1183241189" />

Flinks Upload is a feature that you can enable in both Flinks Connect and in your Flinks Dashboard that processes and extracts data from a bank statement.

Before following the instructions below, ensure that you have already [set up Flinks Connect](../connect/flinks-connect/widget#flinks-connect-widget). Then, let your Flinks Representative know that you want to start using Flinks Upload. They will walk you through the following steps:

1. Choose which upload screens you want to enable. For more information about the screens you can choose from, see [How Upload works](./upload-a-file#upload-a-file).
2. Choose how you want to receive an alert when a fraud signal is detected in an uploaded file. You can:
   * Be alerted via a notification
   * Set up Webhooks to deliver fraud alerts to you automatically
3. (Optionally) Customize the text on the upload screen.
4. (Optionally) Set up even listeners if you want to take action on any of the following JavaScript events:
   * Upload component is loaded (COMPONENT\_LOAD\_UPLOAD)
   * Files are added or removed (UPLOAD\_INPUT\_CHANGE)
   * A fraud signal is triggered by our statement validation service (UPLOAD\_INVALID\_FILE)
   * User clicks the Continue button in Flinks Connect (UPLOAD\_SUBMIT)
   * Upload fails (UPLOAD\_ERROR).
5. (Optionally) Call the [/FraudAnalysis endpoint](../../api/upload/endpoints/fraud/fraud-analysis) to check if any fraud signals were detected.

For more information about why you may want to set up an event listener, speak to your Flinks representative.
Once you're set up, you can start uploading files and receiving your data.
