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

# Value Link (Gift Cards)

> Configure Value Link (by Fiserv) gift card payments in Gr4vy to accept gift cards at checkout, including balance checks and split tender.

export const ConnectorHeader = ({data, name: nameProp, method: methodName, logo, category: categoryProp, catalog, providers}) => {
  const [logoStage, setLogoStage] = useState(0);
  const [chipLogoFailed, setChipLogoFailed] = useState(false);
  const [anchors, setAnchors] = useState({});
  useEffect(() => {
    const found = {};
    for (const id of ["capabilities", "supported-countries", "supported-currencies", "supported-payment-methods"]) {
      found[id] = Boolean(document.getElementById(id));
    }
    setAnchors(found);
  }, []);
  const hasData = Boolean(data && data.id);
  if (!hasData && !(nameProp && logo)) return null;
  const CATEGORY_LABELS = {
    card: "Cards",
    bank: "Banking",
    bnpl: "BNPL",
    cash: "Cash vouchers",
    crypto: "Crypto",
    wallet: "Wallets",
    tokenization: "Tokenization"
  };
  const DISPLAY_NAME_OVERRIDES = {
    authorizenet: "Authorize.net",
    cardpointe: "CardPointe",
    cybersource: "Cybersource",
    dlocal: "dLocal",
    shift4i4go: "Shift4 i4go",
    tokenex: "TokenEx",
    "worldine travelhub": "Worldline TravelHub"
  };
  const HIGHLIGHTS = [{
    keys: ["three_d_secure_pass_through", "three_d_secure_hosted"],
    label: "3-D Secure",
    cardOnly: true
  }, {
    keys: ["network_tokens_default", "network_tokens_toggle"],
    label: "Network tokens",
    cardOnly: true
  }, {
    keys: ["digital_wallets"],
    label: "Digital wallets"
  }, {
    keys: ["delayed_capture"],
    label: "Delayed capture"
  }, {
    keys: ["partial_capture"],
    label: "Partial capture"
  }, {
    keys: ["refunds"],
    label: "Refunds"
  }, {
    keys: ["partial_refunds"],
    label: "Partial refunds"
  }, {
    keys: ["zero_auth"],
    label: "Zero auth"
  }, {
    keys: ["settlement_reporting"],
    label: "Settlement reporting"
  }];
  const d = hasData ? data : {};
  const method = d.method || "";
  const provider = !hasData ? "" : method && d.id.endsWith(`-${method}`) ? d.id.slice(0, -(method.length + 1)) : d.id.split("-")[0];
  const fix = value => DISPLAY_NAME_OVERRIDES[(value || "").toLowerCase()] || value || "";
  const name = fix(d.provider) || nameProp || fix(d.displayName) || provider;
  const displayName = fix(d.displayName);
  const productName = !hasData ? "" : method === "card" ? d.provider ? displayName : "" : methodName || (d.provider && displayName !== name ? displayName : "");
  const methodLed = Boolean(productName);
  const cardProduct = methodLed && method === "card";
  const category = categoryProp || (method === "card" && !cardProduct ? "" : CATEGORY_LABELS[d.category] || "");
  const flowLabel = d.category !== "bank" ? "" : d.mode === "bank" ? "Stored in Gr4vy" : d.mode === "redirect" ? "Redirect" : "";
  const providerLogo = hasData ? `/assets/connectors/providers/${provider}.svg` : logo;
  const methodLogo = `/assets/connectors/methods/${method}.svg`;
  const title = methodLed ? productName : name;
  const chipLabel = !hasData ? "" : methodLed ? `via ${name}` : methodName;
  const chipLogo = cardProduct ? "" : methodLed ? providerLogo : methodLogo;
  const logos = methodLed && !cardProduct ? [methodLogo, providerLogo] : [providerLogo];
  const primaryLogo = logos[logoStage] || null;
  const enabled = new Set((d.features || "").split(/\s+/).filter(Boolean));
  const highlights = HIGHLIGHTS.filter(h => !(h.cardOnly && method !== "card") && h.keys.some(k => enabled.has(k)));
  const codes = value => (value || "").split(/\s+/).filter(Boolean);
  const providerSet = new Set(codes(providers));
  const members = !hasData && catalog && providerSet.size > 0 ? catalog.filter(e => providerSet.has(e.provider)) : [];
  const union = key => new Set(members.flatMap(e => codes(e[key]))).size;
  const methodsCount = members.length;
  const countries = hasData ? codes(d.supportedCountries).length : union("countries");
  const currencies = hasData ? codes(d.supportedCurrencies).length : union("currencies");
  const border = "1px solid rgba(128, 128, 128, 0.2)";
  const labelStyle = {
    fontSize: "0.6875rem",
    fontWeight: 600,
    letterSpacing: "0.05em",
    textTransform: "uppercase",
    opacity: 0.6
  };
  const chipStyle = {
    display: "inline-flex",
    alignItems: "center",
    gap: "0.3rem",
    padding: "0.1rem 0.5rem",
    borderRadius: "999px",
    border,
    fontSize: "0.8125rem",
    whiteSpace: "nowrap"
  };
  const renderStat = (label, value, anchor) => <a href={anchors[anchor] ? `#${anchor}` : undefined} style={{
    display: "flex",
    flexDirection: "column",
    gap: "0.1rem",
    textDecoration: "none",
    borderBottom: "none",
    color: "inherit",
    minWidth: "6rem"
  }}>
      <span style={labelStyle}>{label}</span>
      <span style={{
    fontSize: "1.25rem",
    fontWeight: 600
  }}>{value}</span>
    </a>;
  return <div className="not-prose" style={{
    border,
    borderRadius: "0.75rem",
    padding: "1.25rem",
    margin: "1rem 0 1.5rem",
    display: "flex",
    flexDirection: "column",
    gap: "1rem"
  }}>
      <div style={{
    display: "flex",
    alignItems: "center",
    gap: "1rem"
  }}>
        {primaryLogo ? <img src={primaryLogo} alt={`${title} logo`} width="56" height="56" onError={() => setLogoStage(logoStage + 1)} style={{
    width: "3.5rem",
    height: "3.5rem",
    borderRadius: "0.5rem",
    margin: 0,
    flexShrink: 0
  }} /> : <span aria-hidden="true" style={{
    width: "3.5rem",
    height: "3.5rem",
    borderRadius: "0.5rem",
    border,
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    fontSize: "1.5rem",
    fontWeight: 600,
    flexShrink: 0
  }}>
            {title.charAt(0).toUpperCase()}
          </span>}
        <div style={{
    display: "flex",
    flexDirection: "column",
    gap: "0.35rem",
    minWidth: 0
  }}>
          <span style={{
    fontSize: "1.25rem",
    fontWeight: 600,
    lineHeight: 1.2
  }}>{title}</span>
          <span style={{
    display: "flex",
    flexWrap: "wrap",
    gap: "0.4rem",
    alignItems: "center"
  }}>
            {chipLabel ? <span style={chipStyle}>
                {chipLogoFailed || !chipLogo ? null : <img src={chipLogo} alt="" width="16" height="16" onError={() => setChipLogoFailed(true)} style={{
    width: "1rem",
    height: "1rem",
    borderRadius: "0.2rem",
    margin: 0
  }} />}
                {chipLabel}
              </span> : null}
            {category ? <span style={{
    ...chipStyle,
    opacity: 0.75
  }}>{category}</span> : null}
            {flowLabel ? <span style={{
    ...chipStyle,
    opacity: 0.75
  }}>{flowLabel}</span> : null}
          </span>
        </div>
      </div>

      {methodsCount > 0 || countries > 0 || currencies > 0 || highlights.length > 0 ? <div style={{
    display: "flex",
    flexWrap: "wrap",
    gap: "1rem 2rem",
    paddingTop: "1rem",
    borderTop: border
  }}>
        {methodsCount > 0 ? renderStat("Payment methods", methodsCount, "supported-payment-methods") : null}
        {}
        {countries > 0 ? renderStat("Countries", countries >= 200 ? "No limit" : countries, "supported-countries") : null}
        {currencies > 0 ? renderStat("Currencies", currencies >= 150 ? "No limit" : currencies, "supported-currencies") : null}
        {highlights.length > 0 ? <div style={{
    display: "flex",
    flexDirection: "column",
    gap: "0.35rem",
    flex: "1 1 16rem"
  }}>
            <span style={labelStyle}>Highlights</span>
            <span style={{
    display: "flex",
    flexWrap: "wrap",
    gap: "0.35rem"
  }}>
              {highlights.map(h => <span key={h.label} style={chipStyle}>
                  <span aria-hidden="true" style={{
    color: "#16a34a",
    fontWeight: 700
  }}>✓</span>
                  {h.label}
                </span>)}
              {anchors.capabilities ? <a href="#capabilities" style={{
    ...chipStyle,
    borderStyle: "dashed",
    textDecoration: "none",
    color: "inherit"
  }}>
                  All capabilities →
                </a> : null}
            </span>
          </div> : null}
      </div> : null}
    </div>;
};

<ConnectorHeader name="Value Link" logo="/assets/connectors/gift-cards/valuelink.svg" category="Gift cards" />

Value Link (by Fiserv) is a gift card platform that enables buyers to pay at checkout using
one or more gift cards. Gift cards can be used alone or split across a traditional payment method.

For a full overview of how gift cards work in Gr4vy, including checking balances, storing
gift cards, and testing, see the [Gift cards guide](/guides/features/gift-cards/overview).

## Setup

Value Link does not provide self-service sign-up. Please work with Fiserv to get set up
and to have your **SVdot product** approved. Once the product is approved, you can generate
your own **Product Key**.

## Credentials

The following credentials are required.

* The **Merchant ID** for the integration. This is provided by Fiserv.
* The **SVdot API Key** from the Fiserv dashboard.
* The **SVdot API Secret** from the Fiserv dashboard.

These credentials can be configured in the dashboard directly when setting up a Value Link
connection, or the details can be securely shared with the solution engineering team
for them to set up.

### Issuing virtual gift cards

[Issuing a virtual gift card](/guides/features/gift-cards/overview#issue-a-virtual-gift-card) uses
Fiserv's Market product rather than SVdot. To issue virtual gift cards, you also need the following
credentials.

* The **Market API Key** for the Market product. This is provided by Fiserv.
* The **Market API Secret** for the Market product. This is provided by Fiserv.

These are separate from the SVdot credentials used for balance checks, redemptions, and physical
card activation, and require their own approval and setup with Fiserv.

<Note>
  Value Link ignores the `currency` field when issuing a virtual gift card. The currency of the
  issued card is determined by your Fiserv Market account configuration instead.
</Note>

### Verifying credentials

When you save a Value Link connection, Gr4vy verifies the configured credentials against Fiserv.
The SVdot credentials are always verified. If you also provided Market credentials, Gr4vy
authenticates against the Market product as well. Verification only succeeds when every set of
credentials you configured is valid.

<Note>
  A failed verification does not identify which product rejected the credentials. If verification
  fails and you configured both products, check both sets of credentials.
</Note>


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