> ## 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.

# Choose a Back-End solution

> Compare API requests and webhooks to choose the right back-end solution for receiving customer data.

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="1183240266" />

If you've chosen Flinks Connect as your front-end solution, the next step to connecting customer accounts is choosing a back-end solution. The back-end solution allows you to receive the end user's financial data.

Flinks offers two back-end configuration options:

* Setting up API requests to receive customer data
* Setting up Webhooks to receive customer data

To learn more about the capabilities and requirements for each option, refer to the table below and to the following sections:

| **SOLUTION** | **RECEIVES END USER DATA**            | **DELIVERED TO YOU AUTOMATICALLY**    | **ERRORS ARE HANDLED AUTOMATICALLY**  |
| :----------- | :------------------------------------ | :------------------------------------ | :------------------------------------ |
| API requests | <Icon icon="check" color="#16a34a" /> | <Icon icon="xmark" color="#dc2626" /> | <Icon icon="xmark" color="#dc2626" /> |
| Webhooks     | <Icon icon="check" color="#16a34a" /> | <Icon icon="check" color="#16a34a" /> | <Icon icon="check" color="#16a34a" /> |

## Setting up API requests to receive data

<Check>
  #### Use this solution if:

  You want to make an API call to Flinks when you are ready to receive customer data.
</Check>

Set up your API to communicate directly with Flinks APIs to receive end-user data. If you choose this back-end integration option, you'll need to set up your servers to make a call to our API each time you want to receive new or refreshed customer data.

For more information about which endpoints to call and how to handle the response, see [Retrieve Account Data](./retrieve-account-data).

## Setting up Webhooks to receive customer data

<Check>
  #### Use this solution if:

  You want to receive customer data automatically, without needing to make API calls.
</Check>

Receive end-user data automatically on a set schedule by setting up Webhooks. A Webhook is a way to set up custom callbacks from our application to yours, so that you receive the data automatically on a schedule that you set.

For more information about Webhooks, see our [API Reference](../../api/connect/webhooks).

<Card title="Types of data you can receive" icon="link" href="./connect-bank-accounts#types-of-data-that-you-can-receive-from-flinks" arrow="true" />
