Create your payment form

Create your payment form
Set up the Solidgate payment form with step-by-step instructions for script loading, container mounting, and payment request configuration
Create payment form setup step 1

This guide simplifies the process of adding the Payment Form to your website. It covers the preparation of the backend, SDK installation, API instance creation, and merchant data setup. Furthermore, it outlines the initialization of the form using various JavaScript frameworks and how to customize its appearance through parameters and styles.

Backend setup

Begin by setting up your backend, a crucial step for successful implementation. Use the Solidgate SDK to integrate the Payment Form seamlessly into your platforms. This SDK offers intuitive features for transactions and payment form customization. To initiate a charge, supply transaction-specific information through paymentIntent object fields.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
{
  "order_id": "123456",
  "order_description": "Premium package",
  "currency": "USD",
  "amount": 50500,
  "order_items": "item1, item2",
  "order_date": "2025-12-21 11:21:30",
  "order_number": 1,
  "settle_interval": 48,
  "authorization_type": "final",
  "retry_attempt": 1,
  "force3ds": true,
  "customer_date_of_birth": "2000-11-21",
  "customer_email": "test@solidgate.com",
  "customer_first_name": "John",
  "customer_last_name": "Snow",
  "customer_phone": "+14155552671",
  "industry_data": {
    "type": "car_rental",
    "car_rental": {
      "agreement_number": "RA1029384",
      "renter_name": "John Snow",
      "pick_up_date": "2026-03-01T11:00:00Z",
      "drop_off_date": "2026-03-05T16:30:00Z",
      "refundability": "partially_refundable",
      "rate": 10000,
      "rate_indicator": "D",
      "days_rented": "4",
      "customer_service_toll_free_number": "8005550123",
      "rental_class_id": "SUV1",
      "tax_exempt_indicator": "N",
      "fuel_charges": 2500,
      "insurance_charges": 3500,
      "no_show_indicator": "N",
      "one_way_drop_off_charges": 4500,
      "return_location_id": "NYC0001234",
      "pick_up_location": {
        "street_line_1": "1 Rental Rd",
        "state": "MA",
        "city": "Boston",
        "country": "USA",
        "postal": "02128"
      },
      "drop_off_location": {
        "street_line_1": "10 Transit St",
        "state": "NY",
        "city": "New York",
        "country": "USA",
        "postal": "10001"
      },
      "distance_limit": {
        "limit": 500,
        "unit": "miles",
        "additional_distance_cost": {
          "amount": 150,
          "currency": "USD"
        }
      }
    }
  },
  "ip_address": "8.8.8.8",
  "dynamic_descriptor": {
    "suffix": "PlanA"
  },
  "traffic_source": "facebook",
  "transaction_source": "main_menu",
  "purchase_country": "USA",
  "geo_country": "USA",
  "geo_city": "New Castle",
  "billing_address": {
    "address": "Street 3D, Apartment 343",
    "country": "USA",
    "state": "DE",
    "city": "New Castle",
    "zip_code": "19720"
  },
  "language": "en",
  "website": "https://google.com",
  "device": "iPhone 8 iOS 12.0",
  "device_sessions": [
    {
      "id": "dsid_3a20_f9c1_4cd8_89d3_1c5",
      "provider": "checkout"
    },
    {
      "id": "a0d24c8a-2b67-4b4b-bd39-d2efbe92a7f0",
      "provider": "airwallex"
    }
  ],
  "platform": "WEB",
  "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (HTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36",
  "order_metadata": {
    "coupon_code": "NY2025",
    "partner_id": "123989"
  },
  "success_url": "https://merchant.example/success",
  "fail_url": "https://merchant.example/fail"
}

Billing flow

Pass Billing-specific fields in paymentIntent for catalog products subscriptions and invoices. Match the scenario to your Billing version.

Product-basedSubscription 1.0Subscription 2.0Invoice
Billing 1.0Billing 1.0Billing 2.0Billing 2.0
Product-based with a one-time product from the Billing catalog.Subscription with a recurring product.Subscription with a Billing customer and one recurring product.Invoice with a Billing customer and a one-time product.
product_id customer_account_id
product_id customer_account_id
checkout.mode subscription customer_id
checkout.mode invoice customer_id
Billing 1.0 uses merchant customer_account_id.
Billing 2.0 uses Billing customer_id from the customer object. Do not send customer_account_id with checkout or repeat customer fields already stored on the customer.

For Subscription 2.0 and Invoice omit top-level currency amount product_id and invoice_id. The Payment Form calculates totals from checkout.line_items.

Select a Billing flow.

Billing 1.0 one-time product payment.
Provide product_id and merchant customer_account_id.

Description

Identifier of the predefined product in UUID v4 format.

Example

faf3b86a-1fe6-4ae5-84d4-ab0651d75db2

Description

Merchant-defined customer ID for Billing 1.0.

This is not Billing 2.0 customer_id.

Example

4dad42f878

Description

Coupon ID in UUID v4 format for a product discount.

Active only when product_id is present.

Example

eb4c6e93-4c53-447a-b215-5d5786af9844

Billing 1.0 recurring subscription payment.
Provide product_id and merchant customer_account_id.

Description

Identifier of the predefined product in UUID v4 format.

Example

faf3b86a-1fe6-4ae5-84d4-ab0651d75db2

Description

Merchant-defined customer ID for Billing 1.0.

This is not Billing 2.0 customer_id.

Example

4dad42f878

Description

Number of payment retries.

Example

1

Description

Coupon ID in UUID v4 format for a product discount.

Active only when product_id is present.

Example

eb4c6e93-4c53-447a-b215-5d5786af9844

Billing 2.0 recurring subscription payment.
Provide a checkout object with mode as subscription and Billing customer_id. Pass exactly one recurring product in line_items.

Description

Recurring subscription payment parameters with one recurring line item, discounts, customer, and subscription data.

Description

Checkout flow type for a recurring subscription payment.

Use subscription as the value.

Example

subscription

Description

Billing 2.0 customer ID in cust_… format.

Do not send merchant customer_account_id with checkout.

Example

cust_01KMG2ABYPF6XS5DMJQ817C429

Description

Merchant-defined reference that identifies the subscription in your system.

Unique within the channel and immutable after creation. Letters digits underscore or hyphen only.

Example

order_ABC-123

Description

Product line item applied to the subscription.

Pass exactly one recurring product. Multiple recurring products are not supported.

Description

Product price ID charged on this line.

Example

fa43b415-5522-4373-b026-a365562f9649

Description

Number of units of product_price_id on this line.

Example

1

Description

Coupon applied to the subscription.

Provide either coupon_id or coupon_code not both.

Description

Coupon ID.

Cannot be used together with coupon_code.

Example

coup_abc123

Description

Coupon code entered by a customer.

Cannot be used together with coupon_id. Alphanumeric characters only.

Example

MAY2026

Description

Subscription configuration.


Description

Subscription description.

Example

Premium plan annual

Description

Custom string key/value pairs attached to the subscription.

At most 10 entries.

Example

1
2
3
4
{
  "campaign": "spring_2026",
  "channel": "ads"
}

Description

Trial period configuration.


Description

Trial pricing model.

Allowed values are free and paid.

Example

paid

Description

Trial duration.


Description

Trial duration in units.

Maximums are day ≤ 365 week ≤ 52 and month ≤ 12.

Example

7

Description

Trial duration unit.

Allowed values are minute hour day week month quarter and year.

Example

day

Description

Trial price in minor units.

Used for paid trials.

Example

199

Description

Delay before automatic settlement of the paid trial charge, in hours.

Example

48

Billing 2.0 one-time invoice checkout.
Provide a checkout object with mode as invoice and Billing customer_id.

Description

One-time invoice payment parameters with line items discounts and customer details.

Description

Checkout flow type for a one-time invoice payment.

Use invoice as the value.

Example

invoice

Description

Billing 2.0 customer ID in cust_… format.

Do not send merchant customer_account_id with checkout.

Example

cust_01KMG2ABYPF6XS5DMJQ817C429

Description

Merchant-defined reference that identifies the invoice in your system.

Unique within the channel and immutable after creation. Letters digits underscore or hyphen only.

Example

order_ABC-123

Description

Product line item applied to the invoice.


Description

Product price ID charged on this line.

Example

fa43b415-5522-4373-b026-a365562f9649

Description

Number of units of product_price_id on this line.

Example

2

Description

Per-line description shown on the invoice.

Example

Premium plan

Description

Coupon applied to the cart.

Provide either coupon_id or coupon_code not both.

Description

Coupon ID.

Cannot be used together with coupon_code.

Example

coup_abc123

Description

Coupon code entered by a customer.

Cannot be used together with coupon_id. Alphanumeric characters only.

Example

MAY2026

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
{
  "order_id": "123456",
  "order_description": "Premium package",
  "currency": "USD",
  "product_id": "47f95c95-3647-4c5b-ae6d-40fd8d3ac742",
  "coupon_id": "eb4c6e93-4c53-447a-b215-5d5786af9844",
  "customer_account_id": "4dad42f808",
  "order_items": "item1, item2",
  "order_date": "2025-12-21 11:21:30",
  "order_number": 1,
  "settle_interval": 48,
  "authorization_type": "final",
  "retry_attempt": 1,
  "force3ds": true,
  "customer_date_of_birth": "2000-11-21",
  "customer_email": "test@solidgate.com",
  "customer_first_name": "John",
  "customer_last_name": "Snow",
  "customer_phone": "+14155552671",
  "ip_address": "8.8.8.8",
  "dynamic_descriptor": {
    "suffix": "PlanA"
  },
  "traffic_source": "facebook",
  "transaction_source": "main_menu",
  "purchase_country": "CHN",
  "geo_country": "GBR",
  "geo_city": "New Castle",
  "billing_address": {
    "address": "Street 3D, Apartment 343",
    "country": "USA",
    "state": "DE",
    "city": "New Castle",
    "zip_code": "19720"
  },
  "language": "en",
  "website": "https://google.com",
  "device": "iPhone 8 iOS 12.0",
  "device_sessions": [
    {
      "id": "dsid_3a20_f9c1_4cd8_89d3_1c5",
      "provider": "checkout"
    },
    {
      "id": "a0d24c8a-2b67-4b4b-bd39-d2efbe92a7f0",
      "provider": "airwallex"
    }
  ],
  "platform": "WEB",
  "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (HTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36",
  "order_metadata": {
    "coupon_code": "NY2025",
    "partner_id": "123989"
  },
  "success_url": "https://merchant.example/success",
  "fail_url": "https://merchant.example/fail"
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
{
  "order_id": "123456",
  "order_description": "Premium package",
  "currency": "USD",
  "product_id": "faf3b86a-1fe6-4ae5-84d4-ab0651d75db2",
  "coupon_id": "eb4c6e93-4c53-447a-b215-5d5786af9844",
  "customer_account_id": "4dad42f808",
  "order_items": "item1, item2",
  "order_date": "2025-12-21 11:21:30",
  "order_number": 1,
  "settle_interval": 48,
  "authorization_type": "final",
  "retry_attempt": 1,
  "force3ds": true,
  "customer_date_of_birth": "2000-11-21",
  "customer_email": "test@solidgate.com",
  "customer_first_name": "John",
  "customer_last_name": "Snow",
  "customer_phone": "+14155552671",
  "ip_address": "8.8.8.8",
  "dynamic_descriptor": {
    "suffix": "PlanA"
  },
  "traffic_source": "facebook",
  "transaction_source": "main_menu",
  "purchase_country": "CHN",
  "geo_country": "GBR",
  "geo_city": "New Castle",
  "billing_address": {
    "address": "Street 3D, Apartment 343",
    "country": "USA",
    "state": "DE",
    "city": "New Castle",
    "zip_code": "19720"
  },
  "language": "en",
  "website": "https://google.com",
  "device": "iPhone 8 iOS 12.0",
  "device_sessions": [
    {
      "id": "dsid_3a20_f9c1_4cd8_89d3_1c5",
      "provider": "checkout"
    },
    {
      "id": "a0d24c8a-2b67-4b4b-bd39-d2efbe92a7f0",
      "provider": "airwallex"
    }
  ],
  "platform": "WEB",
  "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (HTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36",
  "order_metadata": {
    "coupon_code": "NY2025",
    "partner_id": "123989"
  },
  "success_url": "https://merchant.example/success",
  "fail_url": "https://merchant.example/fail"
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
{
  "order_id": "123456",
  "order_description": "Premium package",
  "checkout": {
    "mode": "subscription",
    "customer_id": "cust_01KMG2ABYPF6XS5DMJQ817C429",
    "merchant_reference": "order_ABC-123",
    "line_items": [
      {
        "product_price_id": "fa43b415-5522-4373-b026-a365562f9649",
        "quantity": 1
      }
    ],
    "discounts": [
      {
        "coupon_code": "MAY2026"
      }
    ],
    "subscription_data": {
      "description": "Premium plan annual",
      "metadata": {
        "campaign": "spring_2026",
        "channel": "ads"
      },
      "trial": {
        "type": "paid",
        "amount": 199,
        "settle_interval": 48,
        "period": {
          "value": 7,
          "unit": "day"
        }
      }
    }
  },
  "success_url": "https://merchant.example/success",
  "fail_url": "https://merchant.example/fail"
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "order_id": "123456",
  "order_description": "Premium package",
  "checkout": {
    "mode": "invoice",
    "customer_id": "cust_01KMG2ABYPF6XS5DMJQ817C429",
    "merchant_reference": "order_ABC-123",
    "line_items": [
      {
        "product_price_id": "fa43b415-5522-4373-b026-a365562f9649",
        "quantity": 2,
        "description": "Premium plan"
      }
    ],
    "discounts": [
      {
        "coupon_code": "MAY2026"
      }
    ]
  },
  "success_url": "https://merchant.example/success",
  "fail_url": "https://merchant.example/fail"
}

With SDK

Step 1. Install SDK

Install the Solidgate SDK in your environment:

1
composer require solidgate/php-sdk
1
npm install @solidgate/node-sdk
1
go get github.com/solidgate-tech/go-sdk
1
pip3 install solidgate-card-sdk

Step 2. Create SDK instance

To interact with the Solidgate API, create an API instance by calling the API constructor function, passing your Public public_key and Secret secret_key keys as arguments.

1
2
3
4
5
<?php

use SolidGate\API\Api;

$api = new Api('public_key', 'secret_key');
1
2
3
const solidGate = require('@solidgate/node-sdk');

let api = new solidGate.Api("public_key", "private_key");
1
solidgateSdk := solidgate.NewSolidGateApi("public_key", "secret_key")
1
val api = Api(HttpClient(), Credentials("public_key", "secret_key"))
1
2
3
from solidgate import ApiClient

client = ApiClient("public_key", "secret_key")

Step 3. Form intent data

To create a charge, you must provide transaction-related information. This information is contained in a FormInitDTO object, which is created by invoking the formMerchantData function on your API instance. In the example code, this function is called with the paymentIntent object fields.

1
2
3
4
5
6
7
<?php

use SolidGate\API\Api;

$api = new Api('public_key', 'secret_key');

$response = $api->formMerchantData(['JSON payment intent // fill as described in documentation']);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const solidGate = require('@solidgate/node-sdk');

let api = new solidGate.Api("public_key", "private_key");

let paymentIntentData = {
    /// fill it as described in documentation
}
let merchantData = api.formMerchantData(paymentIntentData);

const dataToFront = merchantData.toObject()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
    "encoding/json"
    "fmt"

    solidgate "github.com/solidgate-tech/go-sdk"
)

func main() {
    solidgateSdk := solidgate.NewSolidGateApi("public_key", "secret_key")
    paymentIntent := solidgate.PaymentIntent{} // fill as described in documentation
    paymentIntentBytes, err := json.Marshal(paymentIntent)

    if err != nil {
        fmt.Print(err)
    }

    formInitDto, err := solidgateSdk.FormMerchantData(paymentIntentBytes)

    if err != nil {
        fmt.Print(err)
    }

    // ...
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
val api = Api(HttpClient(), Credentials("public_key", "secret_key"))

val attributes = Attributes(mapOf(
    "amount" to 123,
    "currency" to "USD",
    "customer_email" to "test@example.com",
    "ip_address" to "8.8.8.8",
    "order_description" to "Test subscription",
    "order_id" to "order12345",
    "platform" to "WEB"
))

val response = api.formMerchantData(attributes)
1
2
3
4
5
6
from solidgate import ApiClient

client = ApiClient("public_key", "secret_key")

payment_intent_dict = {} # fill as described in documentation
responseDTO = client.form_merchant_data(payment_intent_dict)

Step 4. Pass generated data to frontend

After you have set up the FormInitDTO and turned it into a simple object, you can effortlessly integrate it into your frontend code by transmitting the paymentIntent encrypted String (during form initialization).

Without SDK

An alternative option for integrating the payment form exists without using the Solidgate SDK.

  1. Prepare server-side code in your preferred programming language and libraries to communicate with the Solidgate API.
  2. Create and encrypt a JSON object with the required fields for a payment transaction.
  3. Once the paymentIntent is encrypted, pass it to the frontend for further processing, such as form initialization.
  4. Integrate the Guide
    Authenticate with the Solidgate API using merchant credentials, configure request signing, and start processing live payment transactions.
    signature
    parameter process with the encryption steps for initializing the form, the flow for paymentIntent encrypted String
    • The customer starts the transaction by providing the necessary payment data.
    • A secure random IV is created with the required size for encryption.
    • The system extracts the required size from the secret key and formats it for encryption.
    • A cipher object is set up with the selected encryption algorithm, mode, and padding, and initialized with the key and IV for encryption.
    • The input data is converted into bytes and encrypted using the initialized cipher.
    • The IV and encrypted data become combined into a single byte array for secure transmission, ensuring compatibility and security, such as using the pycryptodome Reference library in Python 3 environments.
    • The combined IV and encrypted data become encoded into a Base64 string for safe transmission over the network.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php

class PaymentIntentGenerator
{
    private string $secretKey;

    public function __construct(string $secretKey)
    {
        $this->secretKey = $secretKey;
    }

    private function generateEncryptedFormData(array $attributes): string
    {
        $attributes = json_encode($attributes);
        $secretKey = substr($this->secretKey, 0, 32);

        $ivLen = openssl_cipher_iv_length('aes-256-cbc');
        $iv = openssl_random_pseudo_bytes($ivLen);

        $encrypt = openssl_encrypt($attributes, 'aes-256-cbc', $secretKey, OPENSSL_RAW_DATA, $iv);

        return $this->base64UrlEncode($iv . $encrypt);
    }

    private function base64UrlEncode($data): string
    {
        return str_replace(['+', '/'], ['-', '_'], base64_encode($data));
    }

    public function testGenerateEncryptedFormData(): void
    {
        $attributes = [
            "order_id" => "order_id",
            "amount" => 1100,
            "currency" => "USD",
            "order_description" => "description",
            "customer_email" => "test@yourdomain.com",
            "ip_address" => "8.8.8.8",
            "platform" => "WEB",
        ];

        $encryptedFormData = $this->generateEncryptedFormData($attributes);
        echo "Encrypted Form Data: " . $encryptedFormData . PHP_EOL;
    }
}

$yourClassInstance = new PaymentIntentGenerator("api_sk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx");
$yourClassInstance->testGenerateEncryptedFormData();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const crypto = require('crypto');

class PaymentIntentGenerator {
    constructor() {
        this.secretKey = "api_sk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx";
    }

    generateIntent() {
        const intent = '{"order_id":"order_id","amount":1100,"currency":"USD","order_description":"description","customer_email":"test@solidgate.com","ip_address":"8.8.8.8","platform":"WEB"}';
        const paymentIntent = this.encryptPaymentIntent(intent, this.secretKey);

        console.log("Generated Payment Intent:");
        console.log(paymentIntent);
    }

    encryptPaymentIntent(value, secretKey) {
        const iv = crypto.randomBytes(16);
        const aesKey = Buffer.from(secretKey.substring(0, 32), 'utf-8');
        const cipher = crypto.createCipheriv("aes-256-cbc", aesKey, iv);

        let encryptedBytes = cipher.update(value, 'utf-8', 'base64');
        encryptedBytes += cipher.final('base64');

        const encryptedWithIV = Buffer.concat([iv, Buffer.from(encryptedBytes, 'base64')]);

        const base64Encoded = encryptedWithIV.toString('base64')
            .replace(/\+/g, '-')
            .replace(/\//g, '_');

        return base64Encoded;
    }
}

const generator = new PaymentIntentGenerator();
generator.generateIntent();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class PaymentIntentGenerator {
  private final String secretKey = "api_sk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx";

  public void generateIntent() throws Exception {
    String intent = "{\"order_id\":\"order_id\",\"amount\":1100,\"currency\":\"USD\",\"order_description\":\"description\",\"customer_email\":\"test@solidgate.com\",\"ip_address\":\"8.8.8.8\",\"platform\":\"WEB\"}";
    String paymentIntent = encryptPaymentIntent(intent, secretKey);

    System.out.println("Generated Payment Intent:");
    System.out.println(paymentIntent);
  }

  public String encryptPaymentIntent(String value, String secretKey) throws Exception {
    byte[] iv = new byte[16];
    new SecureRandom().nextBytes(iv);

    SecretKeySpec aesKey = new SecretKeySpec(secretKey.substring(0, 32).getBytes(StandardCharsets.UTF_8), "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, aesKey, new IvParameterSpec(iv));

    byte[] encryptedBytes = cipher.doFinal(value.getBytes(StandardCharsets.UTF_8));
    byte[] encryptedWithIV = new byte[iv.length + encryptedBytes.length];
    System.arraycopy(iv, 0, encryptedWithIV, 0, iv.length);
    System.arraycopy(encryptedBytes, 0, encryptedWithIV, iv.length, encryptedBytes.length);

    return Base64.getEncoder().encodeToString(encryptedWithIV)
        .replace("+", "-")
        .replace("/", "_");
  }

  public static void main(String[] args) throws Exception {
    PaymentIntentGenerator generator = new PaymentIntentGenerator();
    generator.generateIntent();
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using System;
using System.Security.Cryptography;
using System.Text;

class PaymentIntentGenerator
{
    private string secretKey = "api_sk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx";

    public void GenerateIntent()
    {
        string intent = "{\"order_id\":\"order_id\",\"amount\":1100,\"currency\":\"USD\",\"order_description\":\"description\",\"customer_email\":\"test@solidgate.com\",\"ip_address\":\"8.8.8.8\",\"platform\":\"WEB\"}";
        string paymentIntent = EncryptPaymentIntent(intent, secretKey);

        Console.WriteLine("Generated Payment Intent:");
        Console.WriteLine(paymentIntent);
    }

    public static string EncryptPaymentIntent(string value, string secretKey)
    {
        byte[] iv = new byte[16];
        RandomNumberGenerator.Fill(iv);

        using (RijndaelManaged aesAlg = new RijndaelManaged())
        {
            aesAlg.Key = Encoding.UTF8.GetBytes(secretKey.Substring(0, 32));
            aesAlg.Mode = CipherMode.CBC;
            aesAlg.Padding = PaddingMode.PKCS7;

            using (ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, iv))
            {
                byte[] valueBytes = Encoding.UTF8.GetBytes(value);
                byte[] encryptedBytes = encryptor.TransformFinalBlock(valueBytes, 0, valueBytes.Length);

                byte[] encryptedWithIV = new byte[iv.Length + encryptedBytes.Length];
                Array.Copy(iv, 0, encryptedWithIV, 0, iv.Length);
                Array.Copy(encryptedBytes, 0, encryptedWithIV, iv.Length, encryptedBytes.Length);
                string base64Encoded = Convert.ToBase64String(encryptedWithIV).Replace("+", "-").Replace("/", "_");
                return base64Encoded;
            }
        }
    }

    static void Main()
    {
        PaymentIntentGenerator generator = new PaymentIntentGenerator();
        generator.GenerateIntent();
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package main

import (
    "bytes"
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "io"
)

type PaymentIntentGenerator struct {
    key []byte
}

func NewPaymentIntentGenerator(secretKey string) *PaymentIntentGenerator {
    return &PaymentIntentGenerator{
        key: []byte(secretKey)[:32],
    }
}

func (p *PaymentIntentGenerator) GenerateIntent() (string, error) {
    intent := map[string]interface{}{
        "order_id": "order_id",
        "amount": 1100,
        "currency": "USD",
        "order_description": "description",
        "customer_email": "test@solidgate.com",
        "ip_address": "8.8.8.8",
        "platform": "WEB",
    }

    intentBytes, err := json.Marshal(intent)
    if err != nil {
        return "", fmt.Errorf("marshal: %w", err)
    }

    paymentIntent, err := p.encrypt(intentBytes)
    if err != nil {
        return "", fmt.Errorf("encrypt: %w", err)
    }

    return base64.URLEncoding.EncodeToString(paymentIntent), nil
}

func (p *PaymentIntentGenerator) encrypt(raw []byte) ([]byte, error) {
    data := p.pad(raw)

    block, err := aes.NewCipher(p.key)

    if err != nil {
        return []byte(nil), fmt.Errorf("new cipher: %w", err)
    }

    cipherText := make([]byte, aes.BlockSize+len(data))
    iv := cipherText[:aes.BlockSize]
    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
        return nil, fmt.Errorf("io read: %w", err)
    }

    mode := cipher.NewCBCEncrypter(block, iv)
    mode.CryptBlocks(cipherText[aes.BlockSize:], data)

    return cipherText, nil
}

func (p *PaymentIntentGenerator) pad(data []byte) []byte {
    n := aes.BlockSize - (len(data) % aes.BlockSize)
    pb := make([]byte, len(data)+n)

    copy(pb, data)
    copy(pb[len(data):], bytes.Repeat([]byte{byte(n)}, n))

    return pb
}

func main() {
    generator := NewPaymentIntentGenerator("api_sk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx")
    intent, err := generator.GenerateIntent()
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Printf("Generated Payment Intent: %s", intent)
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.security.SecureRandom
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
import java.util.Base64

class PaymentIntentGenerator {
    private val secretKey = "api_sk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx"

    fun generateIntent() {
        val intent = "{\"order_id\":\"order_id\",\"amount\":1100,\"currency\":\"USD\",\"order_description\":\"description\",\"customer_email\":\"test@solidgate.com\",\"ip_address\":\"8.8.8.8\",\"platform\":\"WEB\"}"
        val paymentIntent = encryptPaymentIntent(intent, secretKey)

        println("Generated Payment Intent:")
        println(paymentIntent)
    }

    fun encryptPaymentIntent(value: String, secretKey: String): String {
        val iv = ByteArray(16)
        SecureRandom().nextBytes(iv)

        val aesKey = SecretKeySpec(secretKey.substring(0, 32).toByteArray(charset("UTF-8")), "AES")
        val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
        cipher.init(Cipher.ENCRYPT_MODE, aesKey, IvParameterSpec(iv))

        val encryptedBytes = cipher.doFinal(value.toByteArray(charset("UTF-8")))
        val encryptedWithIV = ByteArray(iv.size + encryptedBytes.size)
        System.arraycopy(iv, 0, encryptedWithIV, 0, iv.size)
        System.arraycopy(encryptedBytes, 0, encryptedWithIV, iv.size, encryptedBytes.size)

        val base64Encoded = Base64.getEncoder().encodeToString(encryptedWithIV)
            .replace("+", "-")
            .replace("/", "_")

        return base64Encoded
    }
}

fun main() {
    val generator = PaymentIntentGenerator()
    generator.generateIntent()
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes
import base64
import json


class PaymentIntentGenerator:
    def __init__(self):
        self.__key = b'api_sk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx'[:32]
        self.__block_size = 16

    def generate_intent(self):
        intent = {
            "order_id": "order_id",
            "amount": 1100,
            "currency": "USD",
            "order_description": "description",
            "customer_email": "test@solidgate.com",
            "ip_address": "8.8.8.8",
            "platform": "WEB"
        }
        intent_str = json.dumps(intent)
        payment_intent = self.encrypt(intent_str)

        print("Generated Payment Intent:")
        print(payment_intent)

    def encrypt(self, raw):
        raw = pad(raw.encode(), self.__block_size, style='pkcs7')
        iv = get_random_bytes(self.__block_size)
        cipher = AES.new(self.__key, AES.MODE_CBC, iv)
        return base64.urlsafe_b64encode(iv + cipher.encrypt(raw)).decode('utf-8')


if __name__ == "__main__":
    generator = PaymentIntentGenerator()
    generator.generate_intent()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
require 'openssl'
require 'base64'
require 'json'

class PaymentIntentGenerator
  IV_LENGTH = 16
  KEY_LENGTH = 32

  def initialize
    @secret_key = 'api_sk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx'[0, KEY_LENGTH]
  end

  def generate_intent
    intent = {
      order_id: 'order_id',
      amount: 1100,
      currency: 'USD',
      order_description: 'description',
      customer_email: 'test@solidgate.com',
      ip_address: '8.8.8.8',
      platform: 'WEB'
    }

    intent_str = intent.to_json
    payment_intent = encrypt_payload(intent_str)

    puts 'Generated Payment Intent:'
    puts payment_intent
  end

  private

  def encrypt_payload(attributes)
    key = @secret_key
    iv = OpenSSL::Random.random_bytes(IV_LENGTH)
    cipher = OpenSSL::Cipher.new('aes-256-cbc')
    cipher.encrypt
    cipher.key = key
    cipher.iv = iv
    encrypted = cipher.update(attributes) + cipher.final

    base64_encoded = Base64.urlsafe_encode64(iv + encrypted)
    base64_encoded.gsub('+', '-').gsub('/', '_')
  end
end

generator = PaymentIntentGenerator.new
generator.generate_intent

Frontend SDK setup

The Solidgate SDK provides a pre-built interface component for payments. It assists in tokenizing customer data, ensuring that card information never interacts with the merchant’s website.

When starting with the Payment Form, you can use Solidgate official payment form SDK wrapper for different JavaScript frameworks:

These integrations automatically load solid-form.js and offer a convenient interface for form operation. Furthermore, you can use manual installation.

Alternatively, manually add the payment form SDK to your checkout page by inserting the script tag at the end of the HTML file’s <body> tag. Use the Solidgate CDN-hosted form for easy integration, ensuring the latest version and preventing potential issues from script modification.

1
<script src="https://cdn.solidgate.com/js/solid-form.js"></script>
Check the console for a warning that Solidgate PaymentFormSdk is already initialized. If this warning appears, solid-form.js has most likely been loaded and run twice. Remove the unnecessary connection.

Next, create a container for the payment form on your page and assign it a custom ID, as demonstrated below. Avoid setting height or display properties for elements inside the container, including the container itself, to prevent form appearance issues due to CSS conflicts.

The following example specifies a container with the default id of Solidgate SDK.

1
<div id="solid-payment-form-container"></div>

Alternatively, use your own container, passing its id to iframeParams as shown in the example below.

1
2
3
4
5
const data = {
  iframeParams: {
    containerId: 'your-custom-container-id'
  }
}

Form initialization

After completing all the steps and modifying the required parameters, initiate the Solidgate SDK

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import React, { FC } from 'react'
import ReactDOM from 'react-dom';
import Payment, { InitConfig } from "@solidgate/react-sdk"

export const MyPayment: FC<{
  merchantData: InitConfig['merchantData']
  styles?: InitConfig['styles']
  formParams?: InitConfig['formParams']
  width?: string
}> = (props) => {
    return (<Payment
         merchantData={props.merchantData}
         styles={props.styles}
         formParams={props.formParams}
         width={props.width}
    />)
}
1
const form = PaymentFormSdk.init(data);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
  <Payment
      :merchant-data="merchantData"
      :form-params="formParams"
      width="100%"
  />
</template>

<script lang="ts" setup>
import { defineAsyncComponent } from 'vue'
import { InitConfig } from '@solidgate/vue-sdk'
const Payment = defineAsyncComponent(() => import('@solidgate/vue-sdk'))

const merchantData: InitConfig['merchantData'] = {
  merchant: '<<--YOUR MERCHANT ID-->>',
  signature: '<<--YOUR SIGNATURE OF THE REQUEST-->>',
  paymentIntent: '<<--YOUR PAYMENT INTENT-->>'
}

const formParams: InitConfig['formParams'] = {}
</script>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/// in app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { SolidPaymentModule } from '@solidgate/angular-sdk';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    SolidPaymentModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

/// in app.component.ts
import {Component} from '@angular/core';

import {FormType, InitConfig} from "@solidgate/angular-sdk";

@Component({
  selector: 'app-root',
  template: `
    <ngx-solid-payment
      [formParams]="formParams"
      [merchantData]="merchantData"
      width="100%"
    ></ngx-solid-payment>
  `
})
export class AppComponent {
  merchantData: InitConfig['merchantData'] = {
    merchant: '<<--YOUR MERCHANT ID-->>',
    signature: '<<--YOUR SIGNATURE OF THE REQUEST-->>',
    paymentIntent: '<<--YOUR PAYMENT INTENT-->>'
  }

  formParams: InitConfig['formParams'] = {
    formTypeClass: FormType.Default
  }
}

Object data (or InitConfig interface in case of frameworks usage) should contain the:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const data = {
  merchantData: {
    merchant: 'api_pk_7b197...ba108f842',
    signature: 'MjliMzU4ODE3ZDVlM2E1YWZmYzI1NmU4MzU3YjhlODRkMTJmZTk1NjIxOWNiYzFmNDk0N2NkNjk5YTA5Y2Q4NzIzOWIwMTgxZTQwOGExZjFmYWQ1NzQyYjc3ZGRjMzE0MTczYTQ2OGEyMTlmNGI4YzA5ZmNhMTczZDI0ZDBkZmM=',
    paymentIntent: 'E5FKjxw5vRjjIZBKtH_Q9oN1Wmn5icMn720prO4nPB3cYpzC9wLAHwq9IwstmD-YFLFPsdq2Rk9YzRJhxdPEq2KI19fFt1QotX-smH5_xWxGfYcv9rf2Y4v4KWgbjzJylHTDM6eCXVvbdZyVU54vD3sxntN3gFiyuhEzMn8mKoDV0UdIqLN_VsTAdehBUrqk7aPNzXCfSqpy9pCBlpdFNCfgOyHoDXGGS_Z9fK3gCw7usF2v0IU96mQGzdtyEUs1Z2MJYwle7sjEkWNEb9SkpW1zUXEZCFMF8Cu-dn6fWe4cVE2Ok1MDeTE43dySgw9e8GzMxgPmG2YFjg5xcvuedQ=='
  },
  formParams: {
    buttonType: 'default',
    submitButtonText: 'Pay',
    isCardHolderVisible: true,
    hideCvvNumbers: true,
    headerText: 'Enter your debit or credit card details (from merchant)',
    titleText: 'Card info (from merchant)',
    formTypeClass: 'default',
    googleFontLink: '//fonts.googleapis.com/css2?family=DM+Sans:ital@1&display=swap',
    autoFocus: false
  },
  styles: {
    submit_button: {
      'background-color': 'red',
      'font-size': '16px',
      'font-weight': 'bold',
      ':hover': {
        'background-color': 'green'
      },
      form_body: {
        'font-family': 'DM Sans'
      }
    }
  }
}

Form cleanup

You can use form.destroy() to clean up the form instance fully. This method ensures that all associated resources are properly destroyed, including cleaning up the DOM tree and removing any residual event listeners or states that may persist.

1
this.form.destroy()

Handle initialization errors

There might be errors when setting up the Payment Form, and if you encounter them:

  • Verify that paymentIntent contains the required parameters.
  • Confirm that the ip_address added is not private.
  • Verify that the ip_address added matches the selected region if using a VPN.
  • Ensure that the form styles do not have the opacity property set to 0 .
  • Inspect form styles for any elements that could be covering the form area.
  • Ensure that you generate a new order_id for each transaction attempt.

You can Guide
Test every payment scenario including approvals, declines, 3DS challenges, and refunds in the sandbox before going live in production.
test payments
to make sure everything works as expected. If the outlined steps do not resolve the issue, please contact us for further assistance. When contacting, share the details of the issue and the steps you have taken to resolve it.

To change transaction parameters after the form is initialized, see Guide
Update payment form parameters such as amount, currency, and product_id using the partialIntent object and form.update method.
Update payment form
.


Looking for help? Contact us
Stay informed with Changelog