Create in-person card payments
Create payment intents so your merchants can accept card payments from customers using their terminal app.
Prerequisites
- The Stripe Terminal SDK installed and the device initialized.
- A merchant profile with the status Enabled.
- An in-person card payment method with the status Enabled. If you don't have one yet, request the payment method first.
- A project access token, or a user access token with Can manage members rights.
Step 1: Create a payment intent
Call the createInPersonPaymentIntent mutation to create a payment intent.
The mutation returns a secret (Stripe's client secret) that you'll use in the next step with the Stripe SDK.
mutation CreateInPersonPayment {
createInPersonPaymentIntent(
input: {
merchantProfileId: "$YOUR_MERCHANT_PROFILE_ID"
amount: { value: "50", currency: "EUR" }
label: "Payment for order #1234"
externalReference: "order-1234"
}
) {
... on CreateInPersonPaymentIntentSuccessPayload {
paymentIntent {
secret
}
}
... on ForbiddenRejection {
__typename
message
}
... on NotFoundRejection {
__typename
message
}
... on InternalErrorRejection {
__typename
message
}
... on ValidationRejection {
__typename
message
}
}
}
Mutation fields
Field Requirements Legend
| Field | Type | Description | |
|---|---|---|---|
merchantProfileId | ID | ● REQ | ID of the merchant profile accepting the payment. |
amount | AmountInput | ● REQ | Amount for the payment intent. Minimum: €0.50. |
label | String | ○ OPT | Label shown on the merchant's bank statement. |
externalReference | String | ○ OPT | Reference to match the payment with an external system, such as an order ID. |
reference | String | ○ OPT | Payment reference. |
idempotencyKey | String | ○ OPT | Unique key to prevent duplicate payment creation. |
Step 2: Process the payment with the Stripe SDK
After creating the payment intent, use the Stripe Terminal SDK in your terminal app to collect and confirm the payment. This step runs entirely on the device.
2.1: Retrieve the payment intent
Use the secret from step 1 to retrieve the payment intent with the Stripe SDK.
- React Native
- iOS
- Android
const secret = "$PAYMENT_INTENT_SECRET"; // from step 1
const { paymentIntent, error } = await retrievePaymentIntent(secret);
if (error) {
// Handle error
return;
}
let secret = "$PAYMENT_INTENT_SECRET" // from step 1
Terminal.shared.retrievePaymentIntent(clientSecret: secret) { retrieveResult, retrieveError in
if let error = retrieveError {
print("retrievePaymentIntent failed: \(error)")
} else if let paymentIntent = retrieveResult {
// Proceed to collect payment method
}
}
val secret = "$PAYMENT_INTENT_SECRET" // from step 1
Terminal.getInstance().retrievePaymentIntent(
secret,
object : PaymentIntentCallback {
override fun onSuccess(paymentIntent: PaymentIntent) {
// Proceed to collect payment method
}
override fun onFailure(e: TerminalException) {
// Handle error
}
}
)
2.2: Collect the payment method
Call collectPaymentMethod to show the Tap to Pay screen.
This activates the device's NFC reader and prompts the customer to tap their card.
- React Native
- iOS
- Android
const { paymentIntent, error } = await collectPaymentMethod({
paymentIntent: paymentIntent,
enableCustomerCancellation: true,
});
if (error) {
// Handle error
}
let collectConfig = try CollectConfigurationBuilder()
.setEnableCustomerCancellation(true)
.build()
self.collectCancelable = Terminal.shared.collectPaymentMethod(
paymentIntent: paymentIntent,
collectConfig: collectConfig
) { collectResult, collectError in
if let error = collectError {
print("collectPaymentMethod failed: \(error)")
} else if let paymentIntent = collectResult {
// Proceed to confirm
}
}
val cancelable = Terminal.getInstance().collectPaymentMethod(
paymentIntent,
object : PaymentIntentCallback {
override fun onSuccess(paymentIntent: PaymentIntent) {
// Proceed to confirm
}
override fun onFailure(e: TerminalException) {
// Handle error
}
},
CollectConfiguration.Builder()
.setEnableCustomerCancellation(true)
.build()
)
2.3: Confirm the payment intent
Call confirmPaymentIntent to finalize the payment.
The payment is authorized and captured automatically.
If capture fails and you want to offer a retry (for example, with a different card), reuse the same payment intent. Repeat step 2.2, then attempt to confirm again.
- React Native
- iOS
- Android
const { paymentIntent, error } = await confirmPaymentIntent({
paymentIntent: paymentIntent,
});
if (error) {
// Handle error
}
self.confirmCancelable = Terminal.shared.confirmPaymentIntent(
paymentIntent
) { confirmResult, confirmError in
if let error = confirmError {
print("confirmPaymentIntent failed: \(error)")
} else if let confirmedPaymentIntent = confirmResult {
print("confirmPaymentIntent succeeded")
}
}
val cancelable = Terminal.getInstance().confirmPaymentIntent(
paymentIntent,
object : PaymentIntentCallback {
override fun onSuccess(paymentIntent: PaymentIntent) {
// Payment confirmed
}
override fun onFailure(e: TerminalException) {
// Handle error
}
}
)
Merchant payment statuses
After processing, the merchant payment object reflects the payment's lifecycle. Refer to the payment object statuses for the full list.
| Status | Explanation |
|---|---|
Captured | Payment authorized and captured. Funds will be settled to the merchant's account. |
Rejected | Payment declined by the issuer or by Swan. Refer to rejection reasons for details. |
Disputed | Customer disputed the payment for some or all of the amount. |
Refunded | Payment reversed by the merchant for some or all of the amount. |
After the payment
After the payment is captured, the merchant payment object is updated and underlying transactions are created. Refer to card transaction types to understand how they settle.
Refunds are currently not supported for in-person card payments. To initiate a refund, ask your merchant to submit a request to the Swan Support team.