Saving Card Details

Saving Card Details

Save a customer's card for future payments using setup intents. Card details are collected in the browser via the JS SDK — your server never handles raw card data. Once saved, you can charge the card server-side without any customer interaction (see Taking Payments — server-side confirmation).

Flow overview

  1. Create a customer (server)
  2. Add a server endpoint that creates a setup intent and returns the client_secret
  3. On the frontend: get the client_secret, mount the payment element, and confirm the setup via the JS SDK

1. Create a customer (server)

API reference

The Idempotency-Key header lets you safely retry requests if they fail — see Idempotency.

curl -X POST https://api.synaptopay.com/v1/accounts/acct_YOUR_ACCOUNT/customers \
  -H "Authorization: Api-Key $API_KEY" \
  -H "Idempotency-Key: YOUR_UNIQUE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": {
      "full_name": "Jane Smith",
      "email": "[email protected]",
      "phone": "+447700900000"
    }
  }'
{
  "name": "accounts/acct_YOUR_ACCOUNT/customers/cus_CUSTOMER_ID",
  "full_name": "Jane Smith",
  "email": "[email protected]",
  "phone": "+447700900000",
  "create_time": "2025-10-27T19:09:47Z"
}

2. Add a server endpoint to create setup intents (server)

API reference

Add an endpoint to your server that creates a setup intent and returns the client_secret to the frontend. The setup intent must be linked to a customer — this is where the saved card will be stored.

Here's the Synapto API call your endpoint needs to make:

curl -X POST https://api.synaptopay.com/v1/accounts/acct_YOUR_ACCOUNT/setup-intents \
  -H "Authorization: Api-Key $API_KEY" \
  -H "Idempotency-Key: YOUR_UNIQUE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": "accounts/acct_YOUR_ACCOUNT/customers/cus_CUSTOMER_ID"
  }'
{
  "name": "accounts/acct_YOUR_ACCOUNT/setup-intents/seti_SETUP_INTENT_ID",
  "client_secret": "seti_SETUP_INTENT_ID_secret_SECRET",
  "customer": "accounts/acct_YOUR_ACCOUNT/customers/cus_CUSTOMER_ID",
  "state": "REQUIRES_PAYMENT_METHOD"
}

Your endpoint should return the client_secret from the response to the frontend. In the example below, we assume this endpoint is POST /api/create-setup-intent and returns { "clientSecret": "seti_..._secret_..." }.

3. Collect card details and confirm (frontend)

The frontend side has three steps:

  1. Get a client_secret — call your server endpoint from step 2
  2. Create and mount a payment element — this renders a secure card input form (an iframe) inside an empty element on your page. The customer's raw card data never touches your servers.
  3. Confirm the setup — when the customer clicks your submit button, call confirmSetup() to tokenize the card and save it
<!-- Any empty element — the SDK renders the card input form here -->
<div id="card-container"></div>
<!-- Your own submit button — the SDK does not provide one -->
<button id="save-btn">Save Card</button>
<div id="result"></div>

<script src="https://js.synaptopay.com/synapto.js"></script>
<script>
  const syn = Synapto("pk_YOUR_PUBLISHABLE_KEY");

  // 1. Get a client_secret from your server
  fetch("/api/create-setup-intent", { method: "POST" })
    .then((res) => res.json())
    .then(({ clientSecret }) => {
      // 2. Create and mount the payment element
      const paymentElement = syn.paymentElement(clientSecret);
      paymentElement.mount("#card-container");

      // 3. Confirm when the customer clicks save
      document.getElementById("save-btn").addEventListener("click", async () => {
        const { setupIntent, error } = await paymentElement.confirmSetup();

        if (error) {
          document.getElementById("result").textContent = "Error: " + error;
        } else {
          document.getElementById("result").textContent =
            "Card saved: " + setupIntent.payment_method;
        }
      });
    });
</script>

On success, setupIntent.payment_method contains the saved card's resource name (e.g. accounts/acct_YOUR_ACCOUNT/payment-methods/pm_PAYMENT_METHOD_ID). You can display a confirmation in the browser, but you don't need to send the payment method back to your server — get it from the webhook instead.

4. Get notified of saved card (server)

Listen for the setup_intent.succeeded webhook event to store the saved card on your server. The event payload includes the full setup intent, including the payment_method. See Webhooks for setup instructions.

Store the payment_method against the customer — when you're ready to charge them, pass it in a server-side payment intent (see Taking Payments — server-side confirmation).

Listing saved payment methods

API reference

To list the payment methods saved for a customer:

curl -X POST https://api.synaptopay.com/v1/accounts/acct_YOUR_ACCOUNT/payment-methods:list \
  -H "Authorization: Api-Key $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "customer": ["accounts/acct_YOUR_ACCOUNT/customers/cus_CUSTOMER_ID"]
    }
  }'

Setup intent states

StateDescription
REQUIRES_PAYMENT_METHODWaiting for card details to be entered
REQUIRES_CONFIRMATIONCard entered, awaiting confirmation
PROCESSINGConfirmation in progress
SUCCEEDEDCard saved successfully
CANCELEDSetup was canceled