PayPal Advanced Card Fields Indonesia 2026 — Custom Checkout Developer

·ChatBot Cell·13 menit baca
PayPal
PayPal Advanced Card Fields Indonesia 2026 — Custom Checkout Developer
Daftar Isi

PayPal Advanced Card Fields — Custom Checkout Developer Indonesia

Lo developer Indonesia. Mau checkout card dengan styling custom. PayPal Smart Button terlalu rigid. Standard iframe kurang flexible. Solution: PayPal Advanced Card Fields.

PayPal Advanced Card Fields = flexible card input dengan control penuh styling. Tokenization secure. 3DS challenge supported. PCI SAQ-A scope (lowest compliance).

Panduan ini bahas cara implement Advanced Card Fields buat Indonesia developer.

Singkatnya: Advanced Card Fields = custom card UI + secure tokenization + 3DS. PCI SAQ-A, full styling control. Butuh bantu integrate? Chat ChatBot Cell.

1. Apa Itu Advanced Card Fields?

Konsep

  • PayPal Hosted Fields (sebelumnya): iframe-based, mid customization
  • Advanced Card Fields (modern): flexible, individual card elements
  • Pattern mirip Stripe Elements: individual input untuk number, CVV, expiry

Component

  • Card Number Field: separate input
  • Expiry Field: separate input (MM/YY)
  • CVV Field: separate input
  • Name Field: optional
  • Postal Code: optional (AVS)

Architecture

[Your Checkout Page]
    ↓
[Individual iframes per field]
    ↓ (PayPal-hosted, secure)
[Tokenization]
    ↓ (server-side)
[PayPal API: create order with tokenized card]
    ↓
[3DS Challenge (if required)]
    ↓
[Payment Capture]

PCI Compliance Scope

  • SAQ-A (lowest): card data nggak pernah touch your server
  • Iframes PayPal-hosted
  • Tokenization secure
  • Best for developer Indonesia

2. Why Advanced Card Fields?

Pro vs PayPal Smart Button

  • Full styling control: match your brand
  • Custom layout: any grid, any order
  • Individual validation: per field feedback
  • Native form feel: not "popup" experience
  • 3DS integration: explicit control

Pro vs Stripe Elements

  • PayPal ecosystem: combine PayPal + card + Apple Pay
  • PayPal buyer protection: trusted brand
  • Single integration: multiple payment method

Con

  • Slightly more code than Smart Button
  • Learning curve: understand iframe pattern
  • Initial setup: 1-2 hari extra vs Smart Button

3. Setup PayPal Account

Step 1: PayPal Business Account

  • Verified with KTP + NPWP + bank
  • Upgrade ke Payments Pro (optional, kalau perlu advanced feature)
  • Atau Payments Standard cukup buat Advanced Card Fields

Step 2: Create REST App

  1. Visit developer.paypal.com
  2. My Apps → Create App
  3. Name: "my-store-card"
  4. Type: Merchant
  5. Features: enable PayPal Checkout
  6. Save → dapat Client ID + Secret

Step 3: Enable Advanced Card Fields

  • App → Accept Payments → Card Payments
  • Enable: ✅ Advanced Card Fields
  • Enable: ✅ 3D Secure
  • Save

4. Client SDK Setup

Install

npm install @paypal/paypal-js

Loader

// lib/paypal-loader.ts
import { loadScript } from "@paypal/paypal-js";

let paypalPromise: Promise<any> | null = null;

export function loadPayPal() {
  if (!paypalPromise) {
    paypalPromise = loadScript({
      clientId: process.env.NEXT_PUBLIC_PAYPAL_CLIENT_ID!,
      components: "card-fields",
      currency: "USD",
      intent: "capture",
    });
  }
  return paypalPromise;
}

5. Card Fields Component

// app/components/CardFields.tsx
"use client";

import { useEffect, useState, useRef } from "react";
import { loadPayPal } from "@/lib/paypal-loader";

export default function CardFields({ orderId, onApprove }: {
  orderId: string;
  onApprove: (data: any) => void;
}) {
  const [cardField, setCardField] = useState<any>(null);
  const numberRef = useRef<HTMLDivElement>(null);
  const cvvRef = useRef<HTMLDivElement>(null);
  const expiryRef = useRef<HTMLDivElement>(null);
  const nameRef = useRef<HTMLInputElement>(null);
  
  useEffect(() => {
    let card: any;
    
    async function init() {
      const paypal = await loadPayPal();
      
      card = paypal.CardFields({
        style: {
          input: {
            "font-size": "16px",
            "font-family": "Inter, sans-serif",
            color: "#1a1a1a",
          },
          ".invalid": { color: "#dc2626" },
          ".valid": { color: "#16a34a" },
        },
        cardholderName: { placeholder: "Cardholder Name", required: true },
        number: { placeholder: "Card Number" },
        cvv: { placeholder: "CVV" },
        expirationDate: { placeholder: "MM/YY" },
        createOrder: async () => orderId,
        onApprove: (data) => onApprove(data),
        onError: (err) => console.error("Card error:", err),
      });
      
      if (card.isEligible()) {
        card.NameField({ el: "#card-name" }).render("#card-name-container");
        card.NumberField({ el: "#card-number" }).render("#card-number-container");
        card.ExpiryField({ el: "#card-expiry" }).render("#card-expiry-container");
        card.CVVField({ el: "#card-cvv" }).render("#card-cvv-container");
        setCardField(card);
      }
    }
    
    init();
    return () => card?.close?.();
  }, [orderId]);
  
  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (cardField) {
      const result = await cardField.submit({
        cardholderName: nameRef.current?.value,
      });
      if (!result) {
        // Validation failed
      }
    }
  }
  
  return (
    <form onSubmit={handleSubmit} className="space-y-4">
      <div>
        <label>Cardholder Name</label>
        <div id="card-name-container">
          <input id="card-name" ref={nameRef} className="w-full p-3 border rounded" />
        </div>
      </div>
      <div>
        <label>Card Number</label>
        <div id="card-number-container">
          <div id="card-number" />
        </div>
      </div>
      <div className="grid grid-cols-2 gap-4">
        <div>
          <label>Expiry</label>
          <div id="card-expiry-container">
            <div id="card-expiry" />
          </div>
        </div>
        <div>
          <label>CVV</label>
          <div id="card-cvv-container">
            <div id="card-cvv" />
          </div>
        </div>
      </div>
      <button type="submit" className="w-full p-3 bg-yellow-400 text-black rounded">
        Pay Now
      </button>
    </form>
  );
}

6. Server-Side Create Order

// app/api/paypal/create-card-order/route.ts
import { NextRequest, NextResponse } from "next/server";
import { getAccessToken } from "@/lib/paypal/auth";

export async function POST(req: NextRequest) {
  const { items, currency = "USD" } = await req.json();
  
  const total = items.reduce(
    (sum: number, i: { amount: number; quantity: number }) =>
      sum + i.amount * i.quantity,
    0
  );
  
  const token = await getAccessToken();
  
  const res = await fetch(
    `${process.env.PAYPAL_API_BASE}/v2/checkout/orders`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${token}`,
        "Content-Type": "application/json",
        "PayPal-Request-Id": crypto.randomUUID(),
      },
      body: JSON.stringify({
        intent: "CAPTURE",
        purchase_units: [{
          amount: { currency_code: currency, value: total.toFixed(2) },
        }],
        payment_source: {
          card: {
            attributes: {
              verification: { method: "SCA_WHEN_REQUIRED" },
            },
          },
        },
      }),
    }
  );
  
  const order = await res.json();
  return NextResponse.json({ id: order.id });
}

7. 3D Secure (SCA) Integration

Rekomendasi · Sponsored

Promo seru yang cocok buat kamu

Penawaran pilihan dari mitra kami — klik buat lihat detail.

Lihat

Mengandung link afiliasi. Baca disclaimer.

Why 3DS?

  • EU regulation: PSD2 SCA mandatory
  • Fraud reduction: 60-80% fraud drop
  • Liability shift: dari merchant ke bank (post-3DS)

PayPal 3DS Strategy

  • SCA_WHEN_REQUIRED: PayPal decide when to challenge
  • SCA_ALWAYS: always challenge (highest security)
  • SCA_NEVER: never challenge (deprecated buat EU)

Code Trigger

const card = paypal.CardFields({
  // ...
  payment_source: {
    card: {
      attributes: {
        verification: { method: "SCA_WHEN_REQUIRED" },
      },
    },
  },
});

User Experience

  1. User fill card details
  2. Click "Pay"
  3. PayPal detect if 3DS needed
  4. If yes: redirect ke bank challenge page (OTP, biometric, dll)
  5. User complete challenge
  6. Redirect back to checkout
  7. Capture payment

8. Capture with 3DS Result

// app/api/paypal/capture-card-order/route.ts
export async function POST(req: NextRequest) {
  const { orderID } = await req.json();
  
  const token = await getAccessToken();
  
  const res = await fetch(
    `${process.env.PAYPAL_API_BASE}/v2/checkout/orders/${orderID}/capture`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${token}`,
        "Content-Type": "application/json",
      },
    }
  );
  
  const data = await res.json();
  
  if (data.status === "COMPLETED") {
    return NextResponse.json({ success: true, capture: data });
  } else if (data.status === "PAYER_ACTION_REQUIRED") {
    // 3DS challenge needed
    return NextResponse.json({
      success: false,
      actionRequired: true,
      links: data.links,
    });
  } else {
    return NextResponse.json({ success: false, error: data }, { status: 400 });
  }
}

9. Validation + Error Handling

Field Validation

const card = paypal.CardFields({
  inputEvents: {
    onChange: (data) => {
      // data.fields = { 'number': { isValid: true, isEmpty: false }, ... }
      const numberField = document.getElementById("card-number-icon");
      if (data.fields.cardNumber.isValid) {
        numberField?.classList.add("valid");
      } else {
        numberField?.classList.remove("valid");
      }
    },
    onFocus: (data) => {
      const container = document.querySelector(`#${data.containerId}-container`);
      container?.classList.add("focused");
    },
    onBlur: (data) => {
      const container = document.querySelector(`#${data.containerId}-container`);
      container?.classList.remove("focused");
    },
  },
});

Error Display

async function handleSubmit() {
  const result = await cardField.submit();
  
  if (!result) {
    // Show field-level errors
    Object.entries(cardField.getState().fields).forEach(([field, state]: any) => {
      if (!state.isValid && !state.isEmpty) {
        const errorEl = document.getElementById(`${field}-error`);
        errorEl!.textContent = state.message || "Invalid";
      }
    });
  }
}

10. Studi Kasus — Indonesia SaaS Implement Advanced Card Fields

Profil: Bagus, founder Indonesia SaaS subscription. Tech: Next.js 16 + PostgreSQL. Pricing $29/month + $290/year.

Reason Pilih Advanced Card Fields

  • Smart Button kurang flexible untuk monthly recurring
  • Stripe belum support Indonesia native
  • Mau styling 100% match dengan SaaS brand
  • Need 3DS untuk EU customer (PSD2 compliance)

Implementation

  • Day 1-2: SDK setup + loader
  • Day 3-4: Card Fields component dengan styling custom
  • Day 5: 3DS integration + challenge handling
  • Day 6: Validation + error UX
  • Day 7: End-to-end test
  • Day 8: Go-live

Styling Decision

  • Border highlight: #FFD700 (brand yellow)
  • Focus state: #FACC15 with glow
  • Error: #dc2626 red border
  • Success: #16a34a green border
  • Typography: Inter 16px (readable)
  • Layout: 2-column (number full, expiry + CVV side-by-side)

Result Month 1

  • Conversion rate: 4.8% (vs Smart Button 3.9%)
  • 3DS challenge triggered: 12% (EU user)
  • 3DS success rate: 88%
  • Card fraud: 0 cases
  • Customer feedback: positive ("Checkout-nya clean")

Lesson: Advanced Card Fields = +0.9% conversion + full styling control + 3DS compliance.

11. PCI Compliance Scope

SAQ-A (Lowest)

  • Card data nggak pernah touch server lo
  • All card input via PayPal iframe
  • Tokenization PayPal side
  • Lo only handle token (no raw PAN)

SAQ-A-EP

  • If you customize card form (JavaScript touches card field)
  • Slightly more strict

Avoid SAQ-D

  • Kalau card data touch your server = SAQ-D
  • 300+ requirement, audit expensive ($50K+)

With Advanced Card Fields

  • Scope: SAQ-A
  • Audit: self-assessment (~$0)
  • Liability: PayPal handle breach

12. Common Mistake Developer

Mistake 1: Try Access Iframe Content

Mistake: query iframe innerHTML buat card number. Fix: Nggak bisa. Iframe cross-origin. Only PayPal can access.

Mistake 2: Custom Styling Outside style Option

Mistake: CSS inject ke .paypal-input direct. Fix: Use PayPal style config option. Otherwise ignored.

Mistake 3: Skip 3DS Handling

Mistake: nggak handle PAYER_ACTION_REQUIRED. Fix: always check status, redirect to challenge link.

Mistake 4: Test Production Card

Mistake: test real card di production env. Fix: always sandbox first. Test card list (4032035796248364 dll).

Mistake 5: Nggak Verify Webhook

Mistake: trust client-side capture. Fix: always webhook server-side verify.

Mistake 6: Forgetting Edge Case

Mistake: assume all card smooth. Fix: handle decline (4000000000000002), insufficient funds, expired, dll.

Mistake 7: Skip Idempotency

Mistake: retry capture tanpa idempotency key. Fix: PayPal-Request-Id always.

13. Tips Pro Advanced Card Fields

1. Style Consistent dengan Brand

  • Color, font, border match
  • Loading state spinner
  • Success state animation

2. Real-time Validation

  • Show ✓ saat field valid
  • Show ✗ saat invalid
  • Disable submit kalau ada invalid field

3. Detect Card Type

  • PayPal auto-detect Visa, Mastercard, Amex, JCB
  • Show card brand icon
  • Adjust CVV length (3 untuk Visa, 4 untuk Amex)

4. Save Card (Vault)

  • PayPal Vault buat tokenized card storage
  • Return customer: 1-click pay
  • Reduce friction

5. Implement Fraud Detection

  • PayPal Risk API
  • Custom rules (block IP, email domain)
  • AVS + CVV check

6. Multi-Currency Support

  • Show price in user currency
  • Process in their currency
  • Avoid FX loss

7. Handle Decline Gracefully

  • Specific error message ("Card declined, try another")
  • Suggest alternative ("Pakai PayPal balance? Apple Pay?")
  • Save cart buat retry

14. Studi Kasus — Indonesia E-commerce Implement

Profil: TokoBungaJakarta, e-commerce flower delivery. Existing PayPal Smart Button. Add Advanced Card Fields buat higher conversion.

Before

  • Smart Button only
  • Conversion: 2.8% visit → paid
  • Customer feedback: "checkout ribet, kebanyakan popup"

After Implementation

  • Advanced Card Fields inline
  • Conversion: 3.5% (+25%)
  • Customer feedback: "checkout-nya cepat dan clean"

Specific Improvements

  • Card number auto-format (4-4-4-4)
  • Expiry auto MM/YY
  • CVV show/hide toggle
  • Real-time validation
  • Saved card buat return customer

Revenue Impact

  • Conversion lift: +25%
  • Monthly order: 100 → 125
  • AOV: Rp 350K
  • Additional monthly: 25 × Rp 350K = Rp 8.75 juta
  • Annual: Rp 105 juta added revenue

Lesson: Small UX improvement = significant revenue impact.

15. Security Best Practice

1. Always HTTPS

  • SSL wajib (Let's Encrypt free)
  • HSTS header
  • Redirect HTTP → HTTPS

2. Content Security Policy

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://www.paypal.com https://www.gstatic.com;
  frame-src https://www.paypal.com https://js.braintreegateway.com;
  style-src 'self' 'unsafe-inline' https://www.paypal.com;

3. Verify Webhook Signature

  • Always verify PayPal webhook
  • Prevent forged webhook attack
  • Reject invalid signature

4. Don't Log Card Data

  • Never log raw PAN, CVV
  • Use PayPal token only
  • Redact sensitive fields

5. Audit Access

  • Who has access to PayPal dashboard
  • API credentials
  • Multi-user dengan permission

6. Monitor Fraud Pattern

  • Set up fraud alert
  • Block suspicious IP
  • Manual review high-value order

16. Tools Stack Developer

Client SDK

  • @paypal/paypal-js: official loader
  • @paypal/react-paypal-js: React wrapper (kalau pake Smart Button juga)

Server

  • Native fetch: minimal, modern
  • paypal-rest-sdk: legacy (deprecated)

Testing

  • Cypress: E2E
  • Playwright: alternative
  • Sandbox cards: PayPal provide

Monitoring

  • Sentry: error tracking
  • Datadog: APM
  • LogRocket: session replay

17. Checklist Implementasi Advanced Card Fields

Persiapan

  • PayPal Business verified
  • REST App dibuat
  • Advanced Card Fields enabled
  • 3DS verification enabled

Client Setup

  • Install @paypal/paypal-js
  • Loader utility
  • CardFields component
  • Styling match brand

Server Setup

  • OAuth2 token cache
  • Create order endpoint
  • Capture endpoint with 3DS handling
  • Webhook handler + verify

Testing

  • Sandbox test semua card scenario
  • 3DS challenge flow
  • Decline scenarios
  • Multi-currency
  • Mobile + desktop

Go-Live

  • Switch env credentials
  • Test $0.01 real
  • Monitor first 100 transactions
  • Setup alert webhook failure
  • Document runbook

18. FAQ Advanced Card Fields Indonesia

Q: Bisanya Indonesia developer pakai Advanced Card Fields?

A: Bisa. Global feature. No restriction.

Q: Berapa fee transaction?

A: Standar PayPal fee 4.4% + $0.30 international. Same with Smart Button.

Q: Apakah perlu PCI DSS audit?

A: Nggak. SAQ-A self-assessment. PayPal handle card data.

Q: Bisanya dengan Visa/Mastercard Indonesia?

A: Bisa. Card yang issued Indonesia support.

Q: Bisanya recurring subscription?

A: Bisa. Pakai PayPal Vault buat tokenized card storage + recurring.

Q: 3DS wajib Indonesia?

A: Nggak wajib (regulasi Indonesia beda). Tapi recommended buat EU customer.

19. Mitos vs Fakta Advanced Card Fields

Mitos 1: "Advanced Card Fields Ribet"

Fakta: Setup 1-2 hari. ROI cepat via conversion lift.

Mitos 2: "PCI Compliance Mahal"

Fakta: SAQ-A self-assessment. $0 audit.

Mitos 3: "Smart Button Cukup"

Fakta: Smart Button conversion lebih rendah. Custom UI lebih optimal.

Mitos 4: "3DS Bikin Conversion Drop"

Fakta: 3DS modern (frictionless) drop <5%. Worth fraud reduction.

Mitos 5: "Indonesia Card Nggak Support"

Fakta: Visa/Mastercard issued Indonesia support penuh.

20. Verdict — Advanced Card Fields = Premium Checkout Experience

Advanced Card Fields = pilihan premium buat Indonesia developer yang mau full control + higher conversion + 3DS compliance.

Yang paling critical:

  • PCI SAQ-A scope (low compliance)
  • Styling full control (brand consistency)
  • 3DS handling (SCA_WHEN_REQUIRED)
  • Real-time validation (UX)
  • Webhook verify (security)

Yang perlu di-avoid:

  • Access iframe content
  • Skip 3DS handling
  • Test real card di production
  • Skip webhook verify
  • Hardcode credential

Yang always do:

  • Sandbox test lengkap
  • Save card (Vault) buat return customer
  • Fraud detection
  • Monitor conversion rate
  • Update SDK rutin

ChatBot Cell siap bantu setup Advanced Card Fields + styling custom + 3DS integration + production deploy. Plus AI Chatbot buat auto-handle 3DS challenge + alert fraud pattern + recover failed payment. Konsultasi gratis.

👉 Mau custom card checkout? Chat ChatBot Cell