Docs
API 2026-05-27.dahlia Dashboard

Payments

Turn on Apple Pay, register your site and pay as a card with a token of the buyer's data.

An Apple Pay payment is a card payment. The buyer approves the payment on their device, your app or page sends Apple's payment data to Fluveo, and Fluveo turns it into a single-use card token. From there you pay, capture, refund and read events exactly as for any card. Every store uses the same calls.

The flow has four calls:

  1. Check that Apple Pay is on in your payment method configuration.
  2. Register each website where the Apple Pay button shows, as a payment method domain.
  3. Send the Apple Pay payment data to POST /v1/tokens and get a tok_ back.
  4. Pay with the token: make a PaymentMethod from it, or pass it straight to the PaymentIntent.

Turn Apple Pay on#

Your store has one payment method configuration. List it to find its id and see the switches. A new store has Apple Pay on and Google Pay off. Card stays on while either wallet is on.

cURL
curl https://api.fluveo.com/v1/payment_method_configurations \
  -H "Authorization: Bearer sk_test_..."

To turn Apple Pay on, or off, update that configuration with apple_pay[display_preference][preference] set to on or off.

cURL
curl https://api.fluveo.com/v1/payment_method_configurations/pmc_... \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: pmc-apple-pay-on" \
  -d "apple_pay[display_preference][preference]=on"

The answer is the configuration. Apple Pay on reads like this:

apple_pay on the configuration
{
  "apple_pay": {
    "available": true,
    "display_preference": {
      "overridable": null,
      "preference": "on",
      "value": "on"
    }
  }
}

Turned off, available is false and both preference and value are off. The switch says whether a checkout may show the Apple Pay button. A payment you make through the API with a token is not refused when the switch is off. Every parameter is on the configuration update.

Register your website#

A wallet button shows only on a website your store has registered. Create one payment method domain per host name, with the bare host: no scheme, port or path.

cURL
curl https://api.fluveo.com/v1/payment_method_domains \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: pmd-shop-example" \
  -d domain_name=shop.example.com

The domain shows a status for each wallet. With a test key, apple_pay and google_pay are active on a new domain:

200 response (trimmed)
{
  "id": "pmd_1Qx7bIcDeFgHiJkLmNoPqRsT",
  "object": "payment_method_domain",
  "domain_name": "shop.example.com",
  "enabled": true,
  "livemode": false,
  "apple_pay": { "status": "active" },
  "google_pay": { "status": "active" }
}

When a wallet reads inactive, its status_details.error_message says why. Fix what it names, then ask again with POST /v1/payment_method_domains/{id}/validate, which returns the domain with each wallet's new status. POST /v1/payment_method_domains/{id} with enabled=false turns a domain off and enabled=true turns it back on. A domain's status does not turn a wallet on: the configuration's switch does. A store keeps at most 100 domains in each mode. See the domain calls.

Create a token#

When the buyer approves the payment, Apple Pay gives your app or page the payment data (PKPaymentToken's paymentData) and a few facts about the card. Send them to POST /v1/tokens:

Body parameters
  • pk_tokenstringRequired

    Apple's payment data as the device returned it, as JSON. Fluveo reads it once to make the token and never stores it.

  • The card's name as Apple Pay shows it, such as Visa 1881.

  • The card network as Apple Pay names it, such as Visa or MasterCard.

  • Apple Pay's transaction identifier. Each one makes one token. See Test it for its test form.

cURL
curl https://api.fluveo.com/v1/tokens \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: order-3001-token" \
  --data-urlencode 'pk_token={"version":"EC_v1","data":"...","signature":"...","header":{...}}' \
  --data-urlencode "pk_token_instrument_name=Visa 1881" \
  --data-urlencode pk_token_payment_network=Visa \
  --data-urlencode pk_token_transaction_id=2f1c...e9

The answer is a token whose card names Apple Pay. used is false until a PaymentMethod takes it. GET /v1/tokens/{id} reads it again.

200 response (trimmed)
{
  "id": "tok_1Qx7cJdEfGhIjKlMnOpQrStU",
  "object": "token",
  "type": "card",
  "used": false,
  "livemode": false,
  "card": {
    "brand": "Visa",
    "last4": "4242",
    "dynamic_last4": "4242",
    "tokenization_method": "apple_pay",
    "wallet": {
      "apple_pay": { "type": "apple_pay" },
      "type": "apple_pay"
    }
  }
}

The create takes only these four parameters. A card number in any of them is refused with a 400 whose param names that parameter, and no token is made. Every parameter is on the token create.

Pay with the token#

Pick one of two ways. Both make a card PaymentMethod from the token.

Make the PaymentMethod first with card[token], then pay with it like any card:

cURL
curl https://api.fluveo.com/v1/payment_methods \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: order-3001-pm" \
  -d type=card \
  -d "card[token]=tok_1Qx7cJdEfGhIjKlMnOpQrStU"

curl https://api.fluveo.com/v1/payment_intents \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: order-3001-pay" \
  -d amount=1000 \
  -d currency=usd \
  -d "payment_method_types[]=card" \
  -d payment_method=pm_1Qx7dKeFgHiJkLmNoPqRsTuV \
  -d confirm=true

Or pass the token to the PaymentIntent in payment_method_data[card][token], and Fluveo makes the PaymentMethod for you:

cURL
curl https://api.fluveo.com/v1/payment_intents \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: order-3002-pay" \
  -d amount=1000 \
  -d currency=usd \
  -d "payment_method_types[]=card" \
  -d "payment_method_data[type]=card" \
  -d "payment_method_data[card][token]=tok_1Qx7eLfGhIjKlMnOpQrStUvW" \
  -d confirm=true

1000 is $10.00, in the smallest unit of the currency. Send nothing else of a card beside the token: card[number] next to card[token] is a 400 parameter_unknown on card[number]. The payment then moves as any card payment does. capture_method=manual holds it for a later capture, and you fulfil on payment_intent.succeeded. See Cards.

What comes back#

The card shows its wallet in card.wallet on the PaymentMethod, and in payment_method_details.card.wallet on the Charge and in the charge.succeeded event:

payment_method_details.card.wallet on the Charge
{
  "apple_pay": { "type": "apple_pay" },
  "dynamic_last4": "4242",
  "type": "apple_pay"
}

last4 is the last four digits of the buyer's card. dynamic_last4 is the last four of the number the device used in its place. A card paid without a wallet shows wallet as null.

A token pays once#

A token makes one PaymentMethod. Sending it a second time, in card[token] or payment_method_data[card][token], is a 400 with code token_already_used on param token, and the token reads used: true.

The PaymentMethod made from it also pays once. Confirming another PaymentIntent with it is a 400 with no code and no param, whose message starts with "The provided PaymentMethod was previously used with a PaymentIntent without Customer attachment" and ends with "It may not be used again. To use a PaymentMethod multiple times, you must attach it to a Customer first." For the buyer's next purchase, ask Apple Pay for new payment data and make a new token.

Refunds#

Refund an Apple Pay payment as you refund any card payment: POST /v1/refunds with the payment_intent and, for part of it, an amount. See Refund a payment.

Test it#

With a test key, you need no device. Put a test form in pk_token_transaction_id and Fluveo makes the token of a test card, whatever pk_token holds:

text
ApplePayStubs~<test card number>~<amount>~<currency>~<anything>
cURL
curl https://api.fluveo.com/v1/tokens \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: test-token-order-abc" \
  --data-urlencode 'pk_token={"version":"EC_v1","data":"","signature":"","header":{}}' \
  --data-urlencode "pk_token_instrument_name=Simulated Instrument" \
  --data-urlencode pk_token_payment_network=Visa \
  --data-urlencode "pk_token_transaction_id=ApplePayStubs~4242424242424242~1000~USD~order-abc"

The token's card is the test card, and its dynamic_last4 is the card number's last four, 4242 here. Each transaction id makes one token, so give each test token a new last part. Write that part in letters: a run of digits there that forms a valid card number is refused. The test form works only with a test key.

Errors#

Every refusal below is a 400 with type invalid_request_error.

Whencodeparammessage
pk_token is not Apple Pay payment data Fluveo can readnonenone"The Apple Pay payment data isn't formatted correctly. Create new payment data using a current Fluveo mobile SDK: https://docs.fluveo.com/apple-pay"
A second token from the same pk_token_transaction_idnonenone"This transaction approval has already been used to create a token."
pk_token_payment_network sent emptyparameter_invalid_emptypk_token_payment_network"You passed an empty string for 'pk_token_payment_network'. We assume empty values are an attempt to unset a parameter; however 'pk_token_payment_network' cannot be unset. You should remove 'pk_token_payment_network' from your request or supply a non-empty value."
A token sent a second timetoken_already_usedtoken"The token tok_... has already been used. Each token can only be used once to create a source."
card[token] or payment_method_data[card][token] names no token of your storenonetoken"Invalid token id: tok_..."
GET /v1/tokens/{id} of a token your store does not haveresource_missingtoken"No such token: 'tok_...'"
A PaymentMethod made from a token, used againnonenone"The provided PaymentMethod was previously used with a PaymentIntent without Customer attachment, ..." (see A token pays once)
Card turned off while Apple Pay or Google Pay is onnonenone"Invalid configuration. Apple Pay and Google Pay require Card to be enabled."
A 101st domain in one modenonenone"You have reached the maximum of 100 payment method domains."

Make a new token from new Apple Pay data after any of the token errors. See Errors for the error object.

Google Pay#

Google Pay has its own switch, google_pay[display_preference][preference] on the same configuration, off on a new store. Each domain shows its own google_pay status. Tokens read only Apple Pay data: POST /v1/tokens takes pk_token and nothing that carries Google Pay's.

Next#