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

# Adyen - Card

> Connect to Adyen to accept credit and debit card payments.

export const connector = {
  displayName: "Adyen",
  method: "card",
  features: "cancel create_token create_transaction deep_linking delayed_capture delete_token digital_wallets issuer_based_installments multi_capture network_tokens_default open_loop over_capture partial_authorization partial_capture partial_refunds refunds requires_webhook_setup settlement_reporting three_d_secure_hosted three_d_secure_pass_through verify_credentials void zero_auth",
  supportedCountries: "AE AL AM AO AR AT AU AW AZ BA BB BD BE BG BH BM BN BO BR BS BW BY BZ CA CH CN CO CR CU CY CZ DE DJ DK DO DZ EE EG ES ET FI FJ FK FR GB GE GH GI GM GN GR GT GY HK HN HR HT HU IE IL IN IQ IS IT JM JO JP KE KG KH KM KR KW KY KZ LA LB LK LT LU LV LY MA MD MK MM MN MO MR MT MU MV MW MX MY MZ NA NG NI NL NO NP NZ OM PA PE PG PH PK PL PT PY QA RO RS RU RW SA SB SC SE SG SH SI SK SL SO SR ST SV SZ TH TN TO TR TT TW TZ UA UG US UY UZ VE VN VU WS YE ZA ZM",
  supportedCurrencies: "AED ALL AMD AOA ARS AUD AWG AZN BAM BBD BDT BHD BMD BND BOB BRL BSD BWP BYN BZD CAD CHF CNY COP CRC CUP CZK DJF DKK DOP DZD EGP ETB EUR FJD FKP GBP GEL GHS GIP GMD GNF GTQ GYD HKD HNL HTG HUF ILS INR IQD JMD JOD JPY KES KGS KHR KMF KRW KWD KYD KZT LAK LBP LKR LYD MAD MDL MKD MMK MNT MOP MRU MUR MVR MWK MXN MYR MZN NAD NGN NIO NOK NPR NZD OMR PAB PEN PGK PHP PKR PLN PYG QAR RON RSD RUB RWF SAR SBD SCR SEK SGD SHP SLE SOS SRD STN SVC SZL THB TND TOP TRY TTD TWD TZS UAH UGX USD UYU UZS VND VUV WST XAF XCD XCG XOF XPF YER ZAR ZMW"
};

export const ConnectorRegions = ({data, kind, name: nameOverride}) => {
  const [query, setQuery] = useState("");
  const [open, setOpen] = useState(false);
  const isCountries = kind === "countries";
  const raw = data && (isCountries ? data.supportedCountries : data.supportedCurrencies);
  const codes = typeof raw === "string" ? raw.split(/\s+/).filter(Boolean) : Array.isArray(raw) ? raw : [];
  const DISPLAY_NAME_OVERRIDES = {
    authorizenet: "Authorize.net",
    cardpointe: "Fiserv CardPointe",
    dlocal: "dLocal",
    shift4i4go: "Shift4 i4go",
    tokenex: "TokenEx"
  };
  const rawName = data && data.displayName || "";
  const name = nameOverride || DISPLAY_NAME_OVERRIDES[rawName.toLowerCase()] || rawName || "This connector";
  const verb = isCountries ? "supports transactions from buyers in" : "supports processing payments in";
  const noun = isCountries ? "countries" : "currencies";
  if (codes.length === 0) return null;
  let displayNames = null;
  try {
    displayNames = new Intl.DisplayNames(["en"], {
      type: isCountries ? "region" : "currency"
    });
  } catch (e) {
    displayNames = null;
  }
  const resolve = code => {
    if (!displayNames) return null;
    try {
      const resolved = displayNames.of(code);
      return resolved && resolved !== code ? resolved : null;
    } catch (e) {
      return null;
    }
  };
  const MAJOR_CURRENCIES = ["USD", "EUR", "GBP", "CAD", "AUD", "JPY", "CHF", "CNY", "SGD", "HKD", "NZD", "SEK", "NOK", "DKK", "MXN", "BRL", "INR"];
  const items = codes.map(code => ({
    code,
    label: resolve(code)
  }));
  if (isCountries) {
    items.sort((a, b) => (a.label || a.code).localeCompare(b.label || b.code));
  } else {
    const rank = code => {
      const i = MAJOR_CURRENCIES.indexOf(code);
      return i === -1 ? MAJOR_CURRENCIES.length : i;
    };
    items.sort((a, b) => rank(a.code) - rank(b.code) || a.code.localeCompare(b.code));
  }
  if (codes.length <= 3) {
    const parts = items.map(it => isCountries || !it.label ? it.label || it.code : `${it.label} (${it.code})`);
    const joined = parts.length === 1 ? parts[0] : parts.length === 2 ? `${parts[0]} and ${parts[1]}` : `${parts.slice(0, -1).join(", ")}, and ${parts[parts.length - 1]}`;
    return <p>
        {name} {verb} {joined}.
      </p>;
  }
  const chipStyle = {
    display: "inline-flex",
    alignItems: "baseline",
    gap: "0.4rem",
    padding: "0.15rem 0.55rem",
    borderRadius: "0.375rem",
    border: "1px solid rgba(128, 128, 128, 0.25)",
    fontSize: "0.875rem",
    lineHeight: 1.5
  };
  const codeStyle = {
    fontFamily: "var(--font-mono, ui-monospace, monospace)",
    fontWeight: 600,
    fontSize: "0.8125rem"
  };
  const controlStyle = {
    color: "inherit",
    background: "transparent",
    border: "1px solid rgba(128, 128, 128, 0.3)",
    borderRadius: "0.5rem",
    fontSize: "0.875rem"
  };
  const renderChip = it => <span key={it.code} style={chipStyle} title={isCountries ? it.code : it.label || it.code}>
      {isCountries ? it.label || it.code : <span style={codeStyle}>{it.code}</span>}
      {!isCountries && it.label ? <span style={{
    opacity: 0.7
  }}>{it.label}</span> : null}
    </span>;
  const PREVIEW = 5;
  const collapsible = items.length > PREVIEW;
  const q = query.trim().toLowerCase();
  const filtered = q ? items.filter(it => it.code.toLowerCase().includes(q) || it.label && it.label.toLowerCase().includes(q)) : items;
  const expanded = open || q !== "";
  const visible = !collapsible ? items : expanded ? filtered : items.slice(0, PREVIEW);
  const toggle = () => {
    const next = !open;
    setOpen(next);
    if (!next) setQuery("");
  };
  return <div>
      <p>
        {name} {verb} the following {codes.length} {noun}:
      </p>

      {collapsible ? <input type="text" value={query} onChange={e => setQuery(e.target.value)} placeholder={`Filter ${noun}…`} aria-label={`Filter ${noun}`} style={{
    ...controlStyle,
    display: "block",
    width: "100%",
    maxWidth: "22rem",
    padding: "0.4rem 0.7rem",
    margin: "0 0 0.75rem"
  }} /> : null}

      <div style={{
    display: "flex",
    flexWrap: "wrap",
    gap: "0.4rem"
  }}>
        {visible.map(renderChip)}
      </div>

      {q && filtered.length === 0 ? <p style={{
    opacity: 0.7,
    marginTop: "0.6rem"
  }}>
          No {noun} match “{query.trim()}”.
        </p> : null}
      {q && filtered.length > 0 ? <p style={{
    opacity: 0.6,
    fontSize: "0.8125rem",
    marginTop: "0.6rem"
  }}>
          Showing {filtered.length} of {items.length}.
        </p> : null}

      {collapsible && !q ? <button type="button" aria-expanded={open} onClick={toggle} style={{
    ...controlStyle,
    display: "inline-flex",
    alignItems: "center",
    gap: "0.4rem",
    padding: "0.35rem 0.75rem",
    marginTop: "0.75rem",
    cursor: "pointer"
  }}>
          <span aria-hidden="true" style={{
    display: "inline-block",
    transform: open ? "rotate(90deg)" : "none",
    transition: "transform 0.15s ease"
  }}>
            ›
          </span>
          {open ? "Show fewer" : `and ${items.length - PREVIEW} more`}
        </button> : null}
    </div>;
};

export const ConnectorCapabilities = ({data}) => {
  const CAPABILITIES = [{
    keys: ["three_d_secure_hosted"],
    label: "3-D Secure (hosted)",
    description: "Gr4vy-hosted 3DS authentication flow.",
    cardOnly: true
  }, {
    keys: ["three_d_secure_pass_through"],
    label: "3-D Secure (pass-through)",
    description: "Pass through 3DS data authenticated by a third party.",
    cardOnly: true
  }, {
    keys: ["partial_authorization"],
    label: "Partial authorization",
    description: "Support partial approval responses."
  }, {
    keys: ["zero_auth"],
    label: "Zero auth",
    description: "Verify a card without charging it."
  }, {
    keys: ["void"],
    label: "Void",
    description: "Cancel an authorized transaction before capture."
  }, {
    keys: ["direct_capture"],
    label: "Direct capture",
    description: "Capture a payment immediately at authorization.",
    hideWhenUnsupported: true
  }, {
    keys: ["delayed_capture"],
    label: "Delayed capture",
    description: "Authorize a payment and capture it at a later time."
  }, {
    keys: ["partial_capture"],
    label: "Partial capture",
    description: "Capture a portion of the authorized amount."
  }, {
    keys: ["over_capture"],
    label: "Over capture",
    description: "Capture more than the originally authorized amount."
  }, {
    keys: ["refunds"],
    label: "Refunds",
    description: "Refund a captured payment."
  }, {
    keys: ["partial_refunds"],
    label: "Partial refunds",
    description: "Refund a portion of the captured amount."
  }, {
    keys: ["settlement_reporting"],
    label: "Settlement reporting",
    description: "Automatic settlement and reconciliation reporting."
  }, {
    keys: ["create_session"],
    label: "Create session",
    description: "Create a connector session for client-side flows."
  }, {
    keys: ["network_tokens_default", "network_tokens_toggle"],
    label: "Network tokens",
    description: "Network-level tokenization for improved approval rates.",
    cardOnly: true
  }, {
    keys: ["digital_wallets"],
    label: "Digital wallets",
    description: "Apple Pay, Google Pay, and other wallet integrations."
  }, {
    keys: ["payment_method_tokenization", "payment_method_tokenization_toggle"],
    label: "Payment method tokenization",
    description: "Store payment methods outside of transactions."
  }, {
    keys: ["transaction_sync"],
    label: "Transaction sync",
    description: "Synchronize transaction state from the connector."
  }, {
    keys: ["create_token"],
    label: "Tokenization",
    description: "Create a token from card details collected via Secure Fields.",
    hideWhenUnsupported: true
  }, {
    keys: ["delete_token"],
    label: "Delete token",
    description: "Delete a stored token.",
    hideWhenUnsupported: true
  }, {
    keys: ["verify_credentials"],
    label: "Verify credentials",
    description: "Validate the configured credentials against the connector.",
    hideWhenUnsupported: true
  }];
  const raw = data && data.features;
  const enabled = typeof raw === "string" ? new Set(raw.split(/\s+/).filter(Boolean)) : Array.isArray(raw) ? new Set(raw) : new Set(Object.keys(raw || ({})).filter(key => raw[key]));
  const isOn = entry => entry.keys.some(key => enabled.has(key));
  const isNonCard = data && data.method && data.method !== "card";
  const renderGroup = (title, entries, supported) => {
    if (entries.length === 0) return null;
    const mark = supported ? "✓" : "✕";
    const markColor = supported ? "#16a34a" : "#9ca3af";
    return <div style={{
      marginTop: "1rem"
    }}>
        <div style={{
      fontSize: "0.75rem",
      fontWeight: 600,
      letterSpacing: "0.05em",
      textTransform: "uppercase",
      opacity: 0.6,
      marginBottom: "0.25rem"
    }}>
          {title}
        </div>
        {}
        <div role="list">
          {entries.map(entry => <div role="listitem" key={entry.label} style={{
      display: "flex",
      gap: "0.5rem",
      alignItems: "baseline",
      padding: "0.3rem 0",
      opacity: supported ? 1 : 0.7
    }}>
              <span aria-hidden="true" style={{
      color: markColor,
      fontWeight: 700,
      flexShrink: 0
    }}>
                {mark}
              </span>
              <span>
                <strong>{entry.label}</strong>
                {entry.description ? <span style={{
      opacity: 0.85
    }}> — {entry.description}</span> : null}
              </span>
            </div>)}
        </div>
      </div>;
  };
  const visible = isNonCard ? CAPABILITIES.filter(entry => !entry.cardOnly) : CAPABILITIES;
  const supported = visible.filter(isOn);
  const unsupported = visible.filter(entry => !isOn(entry) && !entry.hideWhenUnsupported);
  return <div>
      {renderGroup("Supported", supported, true)}
      {renderGroup("Not supported", unsupported, false)}
    </div>;
};

Adyen is a global payment platform founded in 2006 in Amsterdam, Netherlands. The company provides payment processing solutions for merchants worldwide, serving major clients like Spotify, Uber, and eBay. The platform supports card payments with advanced features like delayed capture, partial refunds, network tokenization, and digital wallet integration across multiple currencies and countries.

## Setup

Please follow the [common Adyen instructions](./adyen) to get set up with Adyen.

After you set up your Adyen account, configure the following settings in the developer area so you can use all features.

Go to **Developers** -> **Additional data** in the Adyen dashboard and then make sure the following fields are selected:

* Recurring Details
* Raw acquirer result
* Payment account reference

## Connector configuration

After setting up your Adyen connector in the dashboard, configure how transactions are routed to it. Choose one of the following options:

* **Using Flow** - Configure Adyen as the target connector in [Flow](/guides/dashboard/flow/overview) to automatically route card transactions to this connector
* **Using the API** - Explicitly set the `payment_service_id` parameter to the Adyen connector ID when creating transactions. This overrides any Flow routing rules.

The connector ID can be found in the dashboard under **Connections** -> **Configured connections**.

## Capabilities

<ConnectorCapabilities data={connector} />

## Supported countries

<ConnectorRegions data={connector} kind="countries" />

## Supported currencies

<ConnectorRegions data={connector} kind="currencies" />

## Integration

To accept card payments with Adyen, use one of Gr4vy's client-side integration methods to securely collect card details. Due to PCI compliance requirements, card data should never be sent directly to your servers.

You can integrate using:

* **[Embed](/guides/payments/embed/quick-start)** - A pre-built, customizable payment form that handles the complete payment flow
* **[Secure Fields](/guides/payments/secure-fields/quick-start)** - Embed card input fields for building custom payment forms while maintaining PCI compliance
* **[Mobile SDKs](/guides/get-started#sdks-and-plugins)** - Native SDKs for iOS, Android, React Native, and other platforms

These methods handle card data collection and tokenization. Once the card details are collected and tokenized, create a transaction through the Gr4vy API, which automatically routes the payment to your configured Adyen connection based on your Flow rules or explicit `payment_service_id` parameter.

### Auto-rescue

Adyen's [auto-rescue](https://docs.adyen.com/online-payments/auto-rescue/cards/) feature is supported
by this connector. This feature automatically retries customer-not-present card transactions
when they are declined on the first request.

To enable this feature, pass in the following connection options for Adyen when making a subsequent payment request.

```json theme={"system"}
POST /transactions

{
    "amount": 1299,
    "country": "US",
    "currency": "USD",
    "intent": "capture",
    "payment_method": {
        "method": "id",
        "id": "7f6fb9ca-eb1c-42c6-9b65-8f1c699b84bd"
    },
    "connection_options": {
        "adyen-card": {
            "autoRescue": true,
            "maxDaysToRescue": 5
        }
    },
    "payment_source": "card_on_file",
    "is_subsequent_payment": true,
    "merchant_initiated": true
}
```

<Note>
  Please note that this feature only works for customer-not-present transaction
  where `is_subsequent_payment` is set to `true`.
</Note>

The following fields need to be set.

* `autoRescue` - A boolean value that enables the feature. This defaults to `false`.
* `maxDaysToRescue` - The rescue window, in days. Can specify between 1 and 48 days. Adyen recommends using a rescue window of one calendar month (30 days).
* `autoRescueScenario` - This is one of the [test scenarios](https://docs.adyen.com/online-payments/auto-rescue/cards/#test-auto-rescue) as defined by Adyen. This only works in sandbox. Please be aware that the webhooks from Adyen in these test scenarios may take a few minutes to arrive.

A transaction is marked as `processing` when a transaction has been accepted for automatic retries using this feature. When a
webhook for a successful payment or an eventual rejection is received, the status is updated accordingly.

<Warning>
  For auto-rescue to work it's important to ensure Adyen has been setup to send
  [webhooks](https://docs.adyen.com/development-resources/webhooks/) in a
  **JSON** format.
</Warning>

### Canceling auto-rescue

While a payment is in the rescue process, the buyer may provide a new payment method or reach out to cancel their subscription. In these scenarios, the rescue process can be canceled.

To cancel the auto-rescue process, perform a [cancel request](/reference/transactions/cancel-transaction) on the transaction.
Once Adyen has processed the cancellation and confirmation via webhook has been received, the transaction is marked as canceled.

### Balance splits

Adyen's [balance splits](https://docs.adyen.com/platforms/online-payments/split-transactions/) feature is supported
by this connector. This feature allows determining where to book the funds at transaction time. Please note
the users' stores can be configured to automatically split all transactions. This means that it is not necessary to
send these split instructions in every payment or capture request.

To enable this feature, pass in the following connection options for Adyen when making a payment request.

```json theme={"system"}
POST /transactions

{
    "amount": 4000,
    "country": "US",
    "currency": "USD",
    "intent": "capture",
    "payment_method": {
        ...
    },
    "connection_options": {
        "adyen-card": {
            "splits": {
                "authorization": [
                    {
                        "account": "MARKETPLACE_ACCOUNT1",
                        "amount": {
                            "currency": "USD",
                            "value": 200
                        },
                        "description": "Marketplace fee",
                        "reference": "YOUR_UNIQUE_REFERENCE1",
                        "type": "BalanceAccount"
                    },
                    {
                        "account": "MARKETPLACE_ACCOUNT2",
                        "amount": {
                            "currency": "USD",
                            "value": 200
                        },
                        "description": "Remainder",
                        "reference": "YOUR_UNIQUE_REFERENCE2",
                        "type": "Remainder"
                    },
                ],
                "capture": [...],
                "refund": [...]
            }
        }
    }
}
```

The split information can be defined to be set at time of authorization, capture, or even for refunds. Please note
the `PUT /transactions/{id}` API can be used to update connection options (and therefore splits) before making a capture
or refund.

Please refer to Adyen's [balance splits](https://docs.adyen.com/platforms/online-payments/split-transactions/) documentation for exact details on each
of the split objects.

### Payouts / original credit transactions

Adyen [Transfers API](https://docs.adyen.com/payouts/payout-service/pay-out-to-cards/) is supported by this connector to enable Payouts/Original Credit Transactions. This feature needs to be enabled in the Adyen "account" for it to work. A balance account id also needs to be provided in the configuration of the Adyen connection in the dashboard. Payouts are funded from this balance account.

### Adyen Pinless Debit Routing

Pinless debit routing allows merchants to route U.S. debit card transactions through regional debit networks (such as NYCE, Star, or Pulse) rather than global schemes like Visa or Mastercard, without requiring the cardholder to enter a PIN. For merchants who want to use Adyen's pinless debit routing, check **Defer selecting scheme for co-badged cards** in the connector credential options. This allows Adyen to make the final routing decision for co-badged cards.

## Testing

For testing in sandbox environments, you can use standard test card numbers. Adyen supports industry-standard test cards for simulating different transaction scenarios:

**Successful transactions:**

* Visa: `4111 1111 1111 1111`
* Mastercard: `5555 5555 5555 4444`
* American Express: `3782 822463 10005`

Use any future expiry date and any 3-digit CVV (4 digits for American Express).

For more test scenarios and additional card numbers, refer to the [Adyen testing documentation](https://docs.adyen.com/development-resources/test-cards/test-card-numbers) or contact your Adyen representative.
