# Pembayaran dengan kartu tanpa autentikasi bank
Membangun integrasi yang lebih sederhana dengan keterbatasan regional.
Integrasi ini mendukung bisnis yang hanya menerima kartu AS dan Kanada. Ini lebih sederhana untuk dibangun, tetapi tidak diskalakan untuk mendukung basis pelanggan global.
### Cara kerja integrasi ini
Bank di wilayah seperti Eropa dan India sering kali memerlukan otentikasi dua faktor untuk mengonfirmasi pembelian. Jika Anda terutama melakukan bisnis di AS dan Kanada, mengabaikan *autentikasi kartu* (A bank might require the customer to authenticate a card payment before processing. Implementation varies by bank but commonly consists of a customer entering in a security code sent to their phone) dapat menyederhanakan integrasi Anda, karena bank jarang memintanya di wilayah ini.
Bila bank memerlukan autentikasi, integrasi dasar ini menolak pembayaran (seperti penolakan kartu) dengan segera, alih-alih menangani autentikasi untuk menyelesaikan pembayaran secara asinkron. Manfaatnya adalah pembayaran langsung berhasil atau ditolak dan konfirmasi pembayaran terjadi di server, sehingga Anda dapat menangani tindakan pascapembayaran segera tanpa *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests).
### Bagaimana perbandingannya dengan integrasi global
| Fitur | Integrasi ini | Integrasi global |
| --------------------------------------------------------------------------- | ------------- | ---------------- |
| Formulir pembayaran custom | ✔ | ✔ |
| Data sensitif tidak pernah berinteraksi dengan server Anda | ✔ | ✔ |
| Berfungsi bagi pelanggan AS dan Kanada Anda | ✔ | ✔ |
| Menolak pembayaran dengan detail kartu yang salah atau tidak ada dana | ✔ | ✔ |
| Menolak pembayaran dengan permintaan autentikasi bank | ✔ | |
| Berfungsi bagi pelanggan global Anda | | ✔ |
| Menangani pembayaran kartu secara otomatis yang memerlukan autentikasi bank | | ✔ |
| Webhook direkomendasikan untuk tugas pascapembayaran | | ✔ |
| Menskalakan dengan mudah ke metode pembayaran lain (misalnya, debit bank) | | ✔ |
Bisnis global atau yang tengah berkembang harus menggunakan [integrasi global](https://docs.stripe.com/payments/accept-a-payment.md) Stripe untuk mendukung permintaan bank bagi autentikasi dua faktor serta memungkinkan pelanggan membayar dengan metode pembayaran yang beragam.
Alur pembayaran yang Anda integrasikan (See full diagram at https://docs.stripe.com/payments/without-card-authentication)
## Buat formulir checkout [Sisi client]
[Elements](https://docs.stripe.com/payments/elements.md), bagian dari Stripe. js, menyediakan komponen UI drop-in untuk mengumpulkan informasi kartu dari pelanggan. Stripe meng-hostingnya dan menempatkannya ke dalam formulir pembayaran Anda sebagai iframe sehingga detail kartu pelanggan tidak pernah mencampuri kode Anda.
#### HTML + JS
Pertama-tama, sertakan skrip [Stripe.js](https://docs.stripe.com/js.md) di bagian kepala setiap halaman pada situs Anda.
```html
```
Menyertakan skrip di setiap halaman situs Anda memungkinkan Anda memanfaatkan Stripe [Fungsionalitas penipuan tingkat lanjut](https://docs.stripe.com/radar.md) dan kemampuan untuk mendeteksi perilaku penjelajahan anomali.
### Persyaratan keamanan
Skrip ini harus selalu dimuat secara langsung dari **js.stripe.com** agar tetap [mematuhi PCI](https://docs.stripe.com/security/guide.md). Anda tidak dapat menyertakan skrip tersebut dalam paket atau host salinannya sendiri.
Bila Anda menggunakan Elements, semua informasi pembayaran diserahkan melalui koneksi HTTPS yang aman.
Alamat halaman yang berisi Elements juga harus dimulai dengan **https://**, bukan **http://**. Untuk informasi selengkapnya tentang mendapatkan sertifikat SSL dan mengintegrasikannya dengan server Anda guna mengaktifkan koneksi HTTPS yang aman, lihat dokumentasi [keamanan](https://docs.stripe.com/security.md).
### Tambahkan Elements ke halaman Anda
Selanjutnya, Anda perlu akun Stripe. [Daftar sekarang](https://dashboard.stripe.com/register).
Buat elemen DOM kosong (kontainer) dengan identifikasi unik di formulir pembayaran Anda.
```html
```
Buat instance [objek Stripe](https://docs.stripe.com/js.md#stripe-function), yang menyediakan [kunci API](https://docs.stripe.com/keys.md) yang dapat Anda publikasikan sebagai parameter pertama. Setelah itu, buat instance [objek Elements](https://docs.stripe.com/js.md#stripe-elements) dan gunakan itu untuk [memasang](https://docs.stripe.com/js.md#element-mount) elemen Kartu di kontainer elemen DOM yang kosong pada halaman.
```javascript
const stripe = Stripe('<>');
const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
```
Gunakan [stripe.createPaymentMethod](https://docs.stripe.com/js/payment_methods/create_payment_method) pada client Anda untuk mengumpulkan detail kartu dan membuat [PaymentMethod](https://docs.stripe.com/api/payment_methods.md) bila pelanggan menyerahkan formulir pembayaran. Kirim identifikasi PaymentMethod ke server Anda.
```javascript
const form = document.getElementById("payment-form");
var resultContainer = document.getElementById('payment-result');
// cardElement is defined in the previous step
cardElement.on('change', function(event) {
if (event.error) {
resultContainer.textContent = event.error.message;
} else {
resultContainer.textContent = '';
}
});
form.addEventListener('submit', async event => {
event.preventDefault();
resultContainer.textContent = '';
const result = await stripe.createPaymentMethod({
type: 'card',
card: cardElement,
});
handlePaymentMethodResult(result);
});
const handlePaymentMethodResult = async ({ paymentMethod, error }) => {
if (error) {
// An error happened when collecting card details, show error in payment form
resultContainer.textContent = error.message;
} else {
// Send paymentMethod.id to your server (see Step 3)
const response = await fetch("/pay", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ payment_method_id: paymentMethod.id })
});
const responseJson = await response.json();
handleServerResponse(responseJson);
}
};
const handleServerResponse = async responseJson => {
if (responseJson.error) {
// An error happened when charging the card, show it in the payment form
resultContainer.textContent = responseJson.error;
} else {
// Show a success message
resultContainer.textContent = 'Success!';
}
};
```
#### React
Pertama-tama, instal [Stripe.js](https://github.com/stripe/stripe-js) dan [React Stripe.js](https://docs.stripe.com/sdks/stripejs-react.md).
```bash
npm install --save @stripe/stripe-js @stripe/react-stripe-js
```
> Panduan ini mengasumsikan bahwa Anda sudah memiliki pengetahuan dasar tentang React dan bahwa Anda sudah menyiapkan proyek React. Jika Anda baru mengenal React, kami sarankan Anda membaca React [Persiapan](https://reactjs.org/docs/getting-started.html) memandu sebelum melanjutkan.
>
> Jika Anda mencari cara cepat untuk mencoba React Stripe.js tanpa perlu membangun proyek baru, mulailah dengan ini [demo di CodeSandbox](https://codesandbox.io/s/react-stripe-official-q1loc?fontsize=14&hidenavigation=1&theme=dark).
### Persyaratan keamanan
Bila Anda menggunakan Elements, semua informasi pembayaran diserahkan melalui koneksi HTTPS yang aman.
Alamat halaman yang berisi Elements juga harus dimulai dengan **https://**, bukan **http://**. Untuk informasi selengkapnya tentang mendapatkan sertifikat SSL dan mengintegrasikannya dengan server Anda guna mengaktifkan koneksi HTTPS yang aman, lihat dokumentasi [keamanan](https://docs.stripe.com/security.md).
### Muat Stripe.js dan tambahkan Elements ke halaman Anda
Untuk menggunakan Elements, bungkus root aplikasi React Anda di penyedia [Elements](https://docs.stripe.com/sdks/stripejs-react.md#elements-provider). Panggil [loadStripe](https://github.com/stripe/stripe-js#loadstripe) dengan kunci yang dapat dipublikasikan dan teruskan `Promise` yang dikembalikan ke penyedia `Elements`.
Mengimpor dan menelepon `loadStripe` di root aplikasi React Anda untuk memanfaatkan Stripe [Fungsionalitas penipuan tingkat lanjut](https://docs.stripe.com/radar.md) dan kemampuannya untuk mendeteksi perilaku penjelajahan anomali.
```jsx
import React from 'react';
import ReactDOM from 'react-dom';
import {Elements} from '@stripe/react-stripe-js';
import {loadStripe} from '@stripe/stripe-js';
import CheckoutForm from './CheckoutForm';
// Make sure to call `loadStripe` outside of a component’s render to avoid
// recreating the `Stripe` object on every render.
const stripePromise = loadStripe("<>");
function App() {
return (
);
};
ReactDOM.render(, document.getElementById('root'));
```
### Buat PaymentMethod
Gunakan `CardElement` dan [stripe.createPaymentMethod](https://docs.stripe.com/js/payment_methods/create_payment_method) pada client Anda untuk mengumpulkan detail kartu dan membuat [PaymentMethod](https://docs.stripe.com/api/payment_methods.md) bila pelanggan menyerahkan formulir pembayaran. Kirim identifikasi PaymentMethod ke server Anda.
Untuk memanggil `stripe.createPaymentMethod` dari komponen formulir pembayaran Anda, gunakan kait [useStripe](https://docs.stripe.com/sdks/stripejs-react.md#usestripe-hook) dan [useElements](https://docs.stripe.com/sdks/stripejs-react.md#useelements-hook). Jika Anda lebih suka komponen kelas tradisional daripada kait, Anda dapat menggunakan [ElementsConsumer](https://docs.stripe.com/sdks/stripejs-react.md#elements-consumer) sebagai gantinya.
#### Kait
```jsx
import React from 'react';
import {useStripe, useElements, CardElement} from '@stripe/react-stripe-js';
export default function CheckoutForm() {
const stripe = useStripe();
const elements = useElements();
const handleSubmit = async (event) => {
// We don't want to let default form submission happen here,
// which would refresh the page.
event.preventDefault();
const result = await stripe.createPaymentMethod({
type: 'card',
card: elements.getElement(CardElement),
billing_details: {
// Include any additional collected billing details.
name: 'Jenny Rosen',
},
});
handlePaymentMethodResult(result);
};
const handlePaymentMethodResult = async (result) => {
if (result.error) {
// An error happened when collecting card details,
// show `result.error.message` in the payment form.
} else {
// Otherwise send paymentMethod.id to your server (see Step 3)
const response = await fetch('/pay', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
payment_method_id: result.paymentMethod.id,
}),
});
const serverResponse = await response.json();
handleServerResponse(serverResponse);
}
};
const handleServerResponse = (serverResponse) => {
if (serverResponse.error) {
// An error happened when charging the card,
// show the error in the payment form.
} else {
// Show a success message
}
};
const handleCardChange = (event) => {
if (event.error) {
// Show `event.error.message` in the payment form.
}
};
return (
);
}
```
## Siapkan Stripe [Sisi server]
Gunakan pustaka resmi untuk membuat permintaan ke API Stripe dari aplikasi Anda:
#### Ruby
```bash
# Available as a gem
sudo gem install stripe
```
```ruby
# If you use bundler, you can add this line to your Gemfile
gem 'stripe'
```
## Lakukan pembayaran [Sisi server]
Siapkan endpoint di server Anda untuk menerima permintaan dari klien.
Stripe menggunakan objek [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) untuk mewakili maksud Anda menagih pembayaran dari pelanggan, melacak upaya charge, dan perubahan status pembayaran di seluruh proses.
Selalu putuskan berapa banyak yang akan di-charge di server, lingkungan tepercaya, bukan di klien. Ini mencegah pelanggan yang berniat jahat untuk dapat memilih harga mereka sendiri.
Buat titik akhir HTTP untuk merespons permintaan AJAX dari langkah 1. Di titik akhir itu, dan putuskan berapa banyak biaya yang akan ditagih kepada pelanggan. Untuk membuat pembayaran, buat PaymentIntent menggunakan ID *PaymentMethod* (PaymentMethods represent your customer's payment instruments, used with the Payment Intents or Setup Intents APIs) dari langkah 1 dengan kode berikut:
#### curl
```curl
# Check the status of the PaymentIntent to make sure it succeeded
curl https://api.stripe.com/v1/payment_intents \
-u <>: \
-d amount=1099 \
-d currency=usd \
# A PaymentIntent can be confirmed some time after creation,
# but here we want to confirm (collect payment) immediately.
-d confirm=true \
-d payment_method="{{PAYMENT_METHOD_ID}}" \
# If the payment requires any follow-up actions from the
# customer, like two-factor authentication, Stripe will error
# and you will need to prompt them for a new payment method.
-d error_on_requires_action=true
```
> Jika Anda mengatur [error_on_requires_action](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-error_on_requires_action) ke `true` ketika mengonfirmasi pembayaran, Stripe pembayaran gagal secara otomatis jika memerlukan autentikasi dua faktor dari pengguna.
#### Respons Payment Intents API
Bila Anda melakukan pembayaran dengan API, responsnya menyertakan status PaymentIntent. Jika berhasil, pembayaran akan berstatus `succeeded`.
```json
{
"id": "pi_0FdpcX589O8KAxCGR6tGNyWj",
"object": "payment_intent",
"amount": 1099,
"charges": {
"object": "list",
"data": [
{
"id": "ch_GA9w4aF29fYajT",
"object": "charge",
"amount": 1099,
"refunded": false,
"status": "succeeded",
}
]
},
"client_secret": "pi_0FdpcX589O8KAxCGR6tGNyWj_secret_e00tjcVrSv2tjjufYqPNZBKZc",
"currency": "usd",
"last_payment_error": null,"status": "succeeded",
}
```
Jika pembayaran ditolak, responsnya menyertakan kode kesalahan dan pesan kesalahan. Berikut merupakan contoh pembayaran yang gagal karena autentikasi dua faktor diperlukan untuk kartu.
```json
{
"error": {"code": "authentication_required",
"decline_code": "authentication_not_handled",
"doc_url": "https://docs.stripe.com/error-codes#authentication-required",
"message": "This payment required an authentication action to complete, but `error_on_requires_action` was set. When you're ready, you can upgrade your integration to handle actions at https://stripe.com/docs/payments/payment-intents/upgrade-to-handle-actions.",
"payment_intent": {
"id": "pi_1G8JtxDpqHItWkFAnB32FhtI",
"object": "payment_intent",
"amount": 1099,
"status": "requires_payment_method",
"last_payment_error": {
"code": "authentication_required",
"decline_code": "authentication_not_handled",
"doc_url": "https://docs.stripe.com/error-codes#authentication-required",
"message": "This payment required an authentication action to complete, but `error_on_requires_action` was set. When you're ready, you can upgrade your integration to handle actions at https://stripe.com/docs/payments/payment-intents/upgrade-to-handle-actions.",
"type": "card_error"
},
},
"type": "card_error"
}
}
```
## Tes integrasi
Stripe menyediakan beberapa kartu percobaan yang dapat Anda gunakan di *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) untuk memastikan integrasi ini siap. Gunakan bersama CVC, kode pos, dan tanggal kedaluwarsa mendatang.
| Nomor | Keterangan |
| ---------------- | ------------------------------------------------------------------------------------------------------------ |
| 4242424242424242 | Berhasil dan segera memproses pembayaran. |
| 4000000000009995 | Selalu gagalkan dengan kode penolakan `insufficient_funds`. |
| 4000002500003155 | Perlu autentikasi, yang di integrasi ini akan digagalkan dengan kode penolakan `authentication_not_handled`. |
Lihat daftar lengkap [kartu percobaan](https://docs.stripe.com/testing.md).
## Upgrade integrasi Anda untuk menangani autentikasi kartu
Integrasi pembayaran Anda untuk pembayaran kartu dasar kini telah selesai. Integrasi ini **menolak kartu yang memerlukan autentikasi selama pembayaran**.
Jika Anda mulai melihat pembayaran di Dasbor yang tercantum sebagai `Failed`, maka Anda perlu [meningkatkan integrasi Anda](https://docs.stripe.com/payments/payment-intents/upgrade-to-handle-actions.md). Integrasi global Stripe menangani pembayaran ini alih-alih menolaknya secara otomatis.