Accept payments on your iOS app
Last updated: March 12, 2025
Information
We are not onboarding new merchants to Frames.
Upgrade to Flow instead, our pre-built, customizable payment user interface. Flow provides a more flexible, scalable, and feature-rich integration.
If you've integrated the Frames iOS SDK to your iOS app, you can tokenize a customer's payment details or security code to use in a payment request.
In a script in your project, add the following code:
1// Import the SDK2import Frames34// Defines customer information to for use in a new BillingForm object5let country = Country(iso3166Alpha2: "GB")67let address = Address(8addressLine1: "123 High St.",9addressLine2: "Flat 456",10city: "London",11zip: "SW1A 1AA",12country: country)1314let phone = Phone(number: "+44 1234567890",15country: country)1617// Creates a new BillingForm and populates it with the defined customer data18let billingFormData = BillingForm(19name: "John Smith",20address: address,21phone: phone)2223/* Configures the payment environment. Providing billingFormData is optional,24but doing so can simplify your customer's checkout experience and improves the25chances of successful tokenization */2627let configuration = PaymentFormConfiguration(28apiKey: "<Your Public Key>",29environment: .sandbox,30supportedSchemes: [.visa, .maestro, .mastercard],31billingFormData: billingFormData)3233// Configures tokenization success and failure states34let completion: ((Result<TokenDetails, TokenRequestError>) -> Void) = { result in35switch result {36case .failure(let failure):37if failure == .userCancelled {38/* Depending on needs, User Cancelled can be handled as an individual39failure to complete, an error, or simply a callback that control is returned */40print("User has canceled")41} else {42print("Failed, received error", failure.localizedDescription)43}44case .success(let tokenDetails):45print("Success, received token", tokenDetails.token)46}47}4849// Displays the forms to the user to collect payment information50let framesViewController = PaymentFormFactory.buildViewController(51configuration: configuration,52style: PaymentStyle(53paymentFormStyle: DefaultPaymentFormStyle(),54billingFormStyle: DefaultBillingFormStyle()),55completionHandler: completion56)57navigationController.pushViewController(framesViewController, animated: true)
Information
You can customize the forms used to collect customers' payment details.
Our iOS SDK also supports handling PKPayment
token data from Apple Pay.
1func handle(payment: PKPayment) {2// Create a CheckoutAPIClient instance with your public key.3let checkoutAPIClient = CheckoutAPIClient(4publicKey: "<Your Public Key>",5environment: .sandbox)67// Get the data containing the encrypted payment information.8let paymentData = payment.token.paymentData910// Request an Apple Pay token.11checkoutAPIClient.createApplePayToken(paymentData: paymentData) { result in12switch result {13case .success(let response):14print(response)15case .failure(let error):16print(error.localizedDescription)17}18}19}
Read more about offering Apple Pay in your app.
When the customer submits the required payment forms, the payment details are sent directly to Checkout.com's servers and tokenized. The tokenized payment details are then sent back to you, for you to use in a payment request.
Information
Checkout.com is fully compliant with the Payment Card Industry Data Security Standards (PCI DSS). If you use one of our UI-based solutions, you are subject to a lower level of PCI compliance (SAQ A).
To request a payment, call the following endpoint from your back end:
post
https://api.checkout.com/payments
For the full API specification, see the API reference.
1{2"source": {3"type": "token",4"token": "tok_4gzeau5o2uqubbk6fufs3m7p54"5},6"amount": 100,7"currency": "USD",8"processing_channel_id": "pc_ovo75iz4hdyudnx6tu74mum3fq",9"reference": "ORD-5023-4E89",10"metadata": {11"udf1": "TEST123",12"coupon_code": "NY2023",13"partner_id": 12398914}15}
1{2"id": "pay_mbabizu24mvu3mela5njyhpit4",3"action_id": "act_mbabizu24mvu3mela5njyhpit4",4"amount": 100,5"currency": "USD",6"approved": true,7"status": "Authorized",8"auth_code": "770687",9"response_code": "10000",10"response_summary": "Approved",11"3ds": {12"downgraded": true,13"enrolled": "N"14},15"risk": {16"flagged": true17},18"source": {19"type": "card",20"id": "src_nwd3m4in3hkuddfpjsaevunhdy",21"billing_address": {22"address_line1": "123 Anywhere St.",23"address_line2": "Apt. 456",24"city": "Anytown",25"state": "AL",26"zip": "123456",27"country": "US"28},29"phone": {30"country_code": "+1",31"number": "555 123 4567"32},33"last4": "4242",34"fingerprint": "F31828E2BDABAE63EB694903825CDD36041CC6ED461440B81415895855502832",35"bin": "424242"36},37"customer": {38"id": "cus_udst2tfldj6upmye2reztkmm4i",39"email": "[email protected]",40"name": "John Smith"41},42"processed_on": "2024-09-10T10:11:12Z",43"reference": "ORD-5023-4E89",44"processing": {45"retrieval_reference_number": "909913440644",46"acquirer_transaction_id": "440644309099499894406"47},48"eci": "06",49"scheme_id": "489341065491658",50"links": {51"self": {52"href": "https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4"53},54"action": {55"href": "https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4/actions"56},57"void": {58"href": "https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4/voids"59},60"capture": {61"href": "https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4/captures"62}63}64}
When you send a 3D secure charge request from your server, you receive a 3D Secure URL. This is available from _links.redirect.href
within the JSON response. You can then pass the 3D Secure URL to a ThreedsWebViewController
in order to handle the verification.
Information
You can use the 3D Secure mobile SDKs to handle 3DS challenges natively instead.
The redirect URLs (success_url
and failure_url
) are set in the Dashboard, but they can be overwritten in the charge request sent from your server. It is important to provide the correct URLs to ensure a successful payment flow.
1let threeDSWebViewController = ThreedsWebViewController(2successUrl: "https://example.com/success",3failUrl: "https://example.com/failure")4threeDSWebViewController.url = "https://example.com/3ds"5threeDSWebViewController.delegate = self
1extension ViewController: ThreedsWebViewControllerDelegate {23func threeDSWebViewControllerAuthenticationDidSucceed(_ threeDSWebViewController: ThreedsWebViewController, token: String?) {4// Handle successful 3DS.5}67func threeDSWebViewControllerAuthenticationDidFail(_ threeDSWebViewController: ThreedsWebViewController) {8// Handle failed 3DS.9}10}
Some regions require you to send a security code when you perform a payment with a stored card.
To remain at PCI compliance level SAQ-A, you can use the SDK's security code component to securely tokenize a security code.
The security code token is returned to your application layer, so that you can submit it when you perform a payment request from your back end.
To start, initialize the security code component:
1var configuration = SecurityCodeComponentConfiguration(2apiKey: "PUBLIC_KEY", // set your public key3environment: Frames.Environment.sandbox) // set the environment
Create a UI view:
1let securityCodeView = SecurityCodeComponent()23securityCodeView.frame = parentView.bounds4parentView.addSubview(securityCodeView)
Alternatively, you can use Storyboard or a nib file to create the UIView.
In your custom class, set Class to SecurityCodeComponent
and Module to Frames
. Then, create an IBOutlet
in the code counterpart:

The SecurityCodeComponentStyle
object allows you modify the component styling.
All standard UIView
styling options are available for use, except for text style.
Information
As the component uses a secure display view, you cannot edit the properties of the inner text field.
By default, the security code view uses a transparent background.
1let style = SecurityCodeComponentStyle(text: .init(),2font: UIFont.systemFont(ofSize: 24),3textAlignment: .natural,4textColor: .red,5tintColor: .red,6placeholder: "Enter here")78configuration.style = style
If you set a card scheme for the component, you can ensure that the security code submitted by the customer is in a valid format for the given card scheme.
If you do not set a card scheme, all 3 and 4 digit security codes are considered valid user entries for all card schemes. You receive an error at the API level if the CVV is invalid and you have not enabled the SDKs front-end validation.
If the user submits an empty field as the security code, the SDK throws a validation error when you call createToken()
, regardless of the card scheme you specified.
Information
For a list of valid scheme name string values, refer to your back end.
1configuration.cardScheme = Card.Scheme(rawValue: "VISA")2// Alternatively, you can use `Card.Scheme.visa` directly
Configure the securityCodeView
object with the configuration parameters you defined in previous steps:
1securityCodeView.configure(with: configuration) { [weak self] isSecurityCodeValid in2DispatchQueue.main.async {3self?.payButton.isEnabled = isSecurityCodeValid4}5Â }
Use the securityCodeView
object to create a token:
1securityCodeView.createToken { [weak self] result in2DispatchQueue.main.async {3switch result {4case .success(let tokenDetails):5self?.showAlert(with: tokenDetails.token, title: "Success")67case .failure(let error):8self?.showAlert(with: error.localizedDescription, title: "Failure")9}10}11}
You can then request a payment using the tokenized security code.