Skip to content

Get started

Last updated: December 19, 2022

Learn how to embed a form in your website or application to accept payments from your customers. We'll walk you through a payment flow using our Frames product, which collects card details through an iframe. The information is sent directly to us, so it never touches your server, and you remain PCI-compliant.

In this guide, we combine our Frames tokenization product with our core Unified Payments API. You can also take advantage of our end-to-end products, Hosted Payments Page and Payment Links, while retaining the same level of PCI compliance.


Frames payment flow

1

You embed the Frames payment form into your website or application.

2

Your customer enters payment details through the payment form.

3

We receive your customer's sensitive information and return a token representing those details. This process is called tokenization.

4

You use the token to make a payment request.

5

You present the payment request to the customer.


Before you start

Make sure you have an account with us. Once you've signed in, navigate to Developers > Keys and create your keys. You'll need a public key to use Frames, and a way to authenticate your payment request. We support OAuth 2.0 and secret keys as authentication mechanisms.


Step 1: Set up your project

The Frames payment flow requires both a client-side and a server-side.

  • Client-side: Reference the Frames script and define where the payment form is displayed.
  • Server-side: Securely send the payment request using your server.

Download project template (optional)

If you use this template, you must set up your own server.

1
<!DOCTYPE html>
2
<html lang="en">
3
<head>
4
<meta charset="utf-8" />
5
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
<title>Checkout Frames v2: Single Frame</title>
7
<link rel="stylesheet" href="normalize.css" />
8
<link rel="stylesheet" href="style.css" />
9
</head>
10
11
<body>
12
<form
13
id="payment-form"
14
method="POST"
15
action="https://merchant.com/charge-card"
16
>
17
<div class="one-liner">
18
<div class="card-frame"></div>
19
<button id="pay-button" disabled>PAY GBP 24.99</button>
20
</div>
21
<p class="error-message"></p>
22
<p class="success-payment-message"></p>
23
</form>
24
25
<script src="https://cdn.checkout.com/js/framesv2.min.js"></script>
26
<script src="app.js"></script>
27
</body>
28
</html>

Step 2: Render Frames Client side

Add the script to your project in your index.html file.

1
<script src="https://cdn.checkout.com/js/framesv2.min.js"></script>

If you use server-side rendering (using your backend), using a framework like Next.js, you can add the script in the head component.

1
<head>
2
<script src="https://cdn.checkout.com/js/framesv2.min.js"></script>
3
</head>

To remain PCI-compliant, payment details must be sent directly to us without interacting with your server. Always load framesv2.min.js from cdn.checkout.com. Do not host the script yourself.

Define the payment form

Add the code for your payment form in your html file. The amount on the payment button has been hard coded for this example.

The Frames script looks for an empty div tag to insert an iframe containing the payment form. If you do not include div tags, the payment form will not be visible in your website or application.

1
<form id="payment-form" method="POST" action="https://merchant.com/charge-card">
2
<div class="one-liner">
3
<div class="card-frame">
4
<!-- Frames will be added here -->
5
</div>
6
<button id="pay-button" disabled>PAY GBP 24.99</button>
7
</div>
8
<p class="error-message"></p>
9
<p class="success-payment-message"></p>
10
</form>

Initialize Frames

In your js file, you need to initialize Frames using your public key. Without this, the iframe will not appear in your website or application.

In our example, we use the init method on the Frames object, which we accessed from the Frames script.

1
Frames.init("pk_sbox_XXXX");

If the iframe is not rendering on your website or application:

  1. Check you are using public the sandbox key, pk_sbox, not just pk_.
  2. Some networks block our frames script - check the Network tab to make sure that resources are loaded.

Step 3: Generate token Client side

Now that Frames is loaded in your website or application, we can use it to tokenize card details.

Add logic to payment button

In your js file, add the example code. This tells Frames to submit the card details and begin the tokenization process.

1
var form = document.getElementById("payment-form");
2
3
form.addEventListener("submit", function (event) {
4
event.preventDefault();
5
Frames.submitCard();
6
});

Listen for card tokenization

Use the Frames.Events.CARD_TOKENIZED event to listen for when details have successfully been tokenized. When this event is triggered, you can access the token value through event.token.

The value returned is the token you need to use to request your payment, so make a note. Tokens begin with tok_. For our example, you can simply copy the token that appears in the example iframe.

1
Frames.addEventHandler(Frames.Events.CARD_TOKENIZED, (event) => {
2
console.log(event.token);
3
});

Enter card details

Use these test card details using either the interactive iframe on this webpage, or on your local machine:

Card Number:4242424242424242
Expiry Date:Any date in the future
CVV:100

If you are testing on your local machine, you will likely only be able to test with Visa, Mastercard and American Express card numbers. If you try and use a test card number for a different scheme, the tokenization will fail and the CARD_TOKENIZATION_FAILED handler will be called.

When you select the pay button in this example iframe, we show you the token underneath the payment form. This is for demonstration purposes only and does not reflect what your customer will see.

Send the token to your server

You need to send the token to your server, so your server has access to it when you request the payment.

Send the token either with the form action when we submit our card details, or with a simple HTTPS post request.


Step 4: Request the payment Server side

We are now working in your server. Because you have a token that simply represents card details, you can handle it on your own server and remain PCI-compliant.

When payment details are tokenized, the token can only be used once and within 15 minutes. If you request a payment using an expired token, the payment will fail.

Send payment request

View our API Reference for authentication guidance, and a complete reference of optional and required fields.

post

https://api.sandbox.checkout.com/payments

In the source object:

  • type should have the value token.
  • token should have your stored token as the value.
1
{
2
"source": {
3
"type": "token",
4
"token": "tok_XXX"
5
},
6
"amount": 24.99,
7
"currency": "USD",
8
"processing_channel_id": "pc_XXX"
9
}
1
<?php
2
3
require '../vendor/autoload.php';
4
5
use Checkout\CheckoutApiException;
6
use Checkout\CheckoutException;
7
use Checkout\CheckoutSdk;
8
use Checkout\Common\Currency;
9
use Checkout\Environment;
10
use Checkout\Payments\Request\PaymentRequest;
11
use Checkout\Payments\Request\Source\RequestTokenSource;
12
use Monolog\Handler\StreamHandler;
13
use Monolog\Logger;
14
15
$log = new Logger("checkout-sdk-php-sample");
16
$log->pushHandler(new StreamHandler("php://stdout"));
17
18
// Initialize Checkout API
19
try {
20
$api = CheckoutSdk::builder()->staticKeys()
21
->environment(Environment::sandbox())
22
->secretKey(getenv("sk_sbox_XXX"))
23
->build();
24
} catch (CheckoutException $e) {
25
$log->error("An exception occurred while initializing Checkout SDK : {$e->getMessage()}");
26
http_response_code(400);
27
}
28
29
$postData = file_get_contents("php://input");
30
$request = json_decode($postData);
31
32
// The token generated by Frames on the client side
33
$requestTokenSource = new RequestTokenSource();
34
$requestTokenSource->token = $request->token;
35
36
$request = new PaymentRequest();
37
$request->source = $requestTokenSource;
38
$request->currency = Currency::$GBP;
39
$request->amount = 2499;
40
$request->processing_channel_id = "pc_XXX";
41
42
try {
43
echo json_encode($api->getPaymentsClient()->requestPayment($request));
44
} catch (CheckoutApiException $e) {
45
$log->error("An exception occurred while processing payment request");
46
http_response_code(400);
47
}

Receive request response

That's it! You've just built your first payment flow with Checkout.com. Continue reading to find out more about different responses and next steps.

If you receive a 201 Success response with approved set to true, your request was successful.

1
{
2
"id": "pay_qzpz6fv4dv2etnarerhvqxsvlm",
3
"action_id": "act_agaoqbtsccie5j2zd6jwdodpg4",
4
"amount": 24.99,
5
"currency": "USD",
6
"approved": true,
7
"status": "Authorized",
8
"auth_code": "631973",
9
"response_code": "10000",
10
"response_summary": "Approved",
11
"balances": {
12
"total_authorized": 24.99,
13
"total_voided": 0,
14
"available_to_void": 24.99,
15
"total_captured": 0,
16
"available_to_capture": 24.99,
17
"total_refunded": 0,
18
"available_to_refund": 0
19
},
20
"risk": {
21
"flagged": false
22
},
23
"source": {
24
"id": "src_usxsfdifd2pebamd734fwsihg4",
25
"type": "card",
26
"phone": {},
27
"expiry_month": 1,
28
"expiry_year": 2027,
29
"scheme": "Visa",
30
"last4": "4242",
31
"fingerprint": "2FE6B057E42927009AA100493441AD7C8E88A82573FCAE69C02D8C919F017895",
32
"bin": "424242",
33
"card_type": "CREDIT",
34
"card_category": "CONSUMER",
35
"issuer_country": "GB",
36
"product_id": "F",
37
"product_type": "Visa Classic",
38
"avs_check": "G",
39
"cvv_check": "Y",
40
"payment_account_reference": "V001763436387291028"
41
},
42
"processed_on": "2022-10-20T13:28:05.5201442Z",
43
"scheme_id": "581305702984089",
44
"processing": {
45
"acquirer_transaction_id": "541740228271589217340",
46
"retrieval_reference_number": "462197862661"
47
},
48
"expires_on": "2022-11-19T13:28:05.5201442Z",
49
"_links": {
50
"self": {
51
"href": "https://api.sandbox.checkout.com/payments/pay_qzpz6fv4dv2etnarerhvqxsvlm"
52
},
53
"actions": {
54
"href": "https://api.sandbox.checkout.com/payments/pay_qzpz6fv4dv2etnarerhvqxsvlm/actions"
55
},
56
"capture": {
57
"href": "https://api.sandbox.checkout.com/payments/pay_qzpz6fv4dv2etnarerhvqxsvlm/captures"
58
},
59
"void": {
60
"href": "https://api.sandbox.checkout.com/payments/pay_qzpz6fv4dv2etnarerhvqxsvlm/voids"
61
}
62
}
63
}

202 Payment asynchronous / further action required

If you requested 3D Secure to be used in the payment, or you have a risk rule that triggers 3D Secure, you will see a 202 response. This indicates that you need to redirect the customer to a page to authenticate the payment.

To check on the status of a pending payment, you can use our get payment details endpoint.

If you need to redirect your customer, there will be a _links.redirect.href property in the response.

1
{
2
"redirect": {
3
"href": "https://api.checkout.com/3ds/pay_mbabizu24mvu3mela5njyhpit4"
4
}
5
}

422 Invalid data was sent

A 422 response means there has been a user error. This response could mean the token expired after 15 minutes, or it was used more than once. You can also review the error_codes array to see what needs to be corrected.

1
{
2
"request_id": "b4ea9ea1-3af6-4b34-8c8e-74cc7e456654",
3
"error_type": "processing_error",
4
"error_codes": ["token_expired"]
5
}

Next steps