Update payment form flow

Before updating parameters, complete create your payment form so the form is initialized on the page.

An initialized form supports two update methods. Use update with partialIntent to change amount , currency , or product_id . Use updateCheckout to replace line items, discounts, or trial terms on a Billing checkout intent. The steps below cover update . Billing checkout intents use Checkout update.

There is no need to call the payment form repeatedly when using multiple tariffs. Request the form once and modify the amount , currency , product_id , or any parameter of the partialIntent object using the form instance’s update method.

To update a Payment Form parameter, generate the signature parameter on your backend. This signature verifies the merchant’s request authenticity on the payment gateway server and originates from the partialIntent encrypted String

Backend setup

Firstly, ensure that the backend is prepared. In the example code, the formUpdate function is called with fields.

Specifically, this method allows updates only to a predefined list of fields, distinct from those available during initial form creation in the paymentIntent object. Updates are limited to select parameters within the partialIntent object.

It is important to note that attempting to update fields not defined in the allowed list results in an error response. Choose your payment scenario to see the fields it requires. Payment amount integer >=0 Required

Description

Order amount in minor units. For example, 1020 means 10 USD and 20 cents. Can be 0 for zero-amount authorization.

Example

1020

Product-based product_id string 36 Required

Description

Identifier of the predefined product in UUID v4 format.

Example

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

customer_account_id string 100 Required

Description

Customer ID in the merchant’s system.

Example

4dad42f878

Subscription 1.0 product_id string 36 Required

Description

Identifier of the predefined product in UUID v4 format.

Example

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

customer_account_id string 100 Required

Description

Customer ID in the merchant’s system.

Example

4dad42f878

currency string 3 Required

Description

Currency in three-letter code per the ISO-4217 Wiki standard.

Example

USD

order_description string 255

Description

Order description in your system and for bank processing.

Highly recommended to keep the description brief to improve the clarity of payment processing, ideally not exceeding 100 characters. It is used in the email receipt sent to the customer.

Example

Premium package

order_items string 255

Description

Order items in UTF-8 code.

Example

item1, item2

order_date string 50

Description

Date of order creation following the ^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$ pattern.

Example

2025-12-21 11:21:30

order_number integer int32

Description

Number of payments by the customer.

Example

1

settle_interval integer [0..240]

Description

Delay before settlement in hours:

  • Visa customer-initiated payments: 240 hours = 10 days
  • Visa merchant-initiated payments: 120 hours = 5 days
  • All other card brands: 168 hours = 7 days
It is highly recommended to validate the value against your payment processor’s PSP limits.

Example

48

force3ds boolean

Description

Routing payments flag for 3DS flow.

Example

true

customer_email string 100

Description

Customer email.

If email on the initialization payment form was:

  • non-empty, you cannot change it to an empty email
  • non-empty, and you provide a new email, the new value is passed
  • empty and you provide a new email, the form uses that email as a prefilled value The customer has the option to change it or to confirm it by submission.

Example

test@solidgate.com

traffic_source string 255

Description

Identifies the marketing or acquisition channel that brought the customer to the transaction.

Example

facebook

transaction_source string 255

Description

Identifies the internal system or flow that triggered the transaction.

Example

main_menu

order_metadata object

Description

Metadata is useful for storing additional, structured information about an object, consisting of up to 10 key-value pairs with a validation limit of 380 characters per field.

The callback notification returns an order_metadata from the order in each state.

Example

{"coupon_code": "NY2025", "partner_id": "123989"}

success_url string 255

Description

Provide this URL if you want to redirect a customer to your own Success Screen.

If you do not provide the URL, Solidgate directs customers to the Solidgate Success Screen. The Solidgate notification screen is not customizable, but you can define your own success and fail pages during Payment Form initialization with success_url and fail_url.

Example

http://merchant.example/success

fail_url string 255

Description

Provide this URL if you want to redirect a customer to your own Fail Screen.

If you do not provide the URL, Solidgate directs customers to the Solidgate Fail Screen.

Example

http://merchant.example/fail

Payment
{
  "amount": 1020,
  "currency": "EUR",
  "order_description": "Premium package",
  "order_items": "item5",
  "order_date": "2025-02-21 11:21:30",
  "order_number": 4,
  "settle_interval": 48,
  "force3ds": true,
  "customer_email": "user-one@mail.com",
  "traffic_source": "Instagram",
  "transaction_source": "Main menu",
  "order_metadata": {
    "coupon_code": "NY2025",
    "partner_id": "123989"
  },
  "success_url": "http://merchant.example/success",
  "fail_url": "http://merchant.example/fail"
}
Product-based
{
  "product_id": "47f95c95-3647-4c5b-ae6d-40fd8d3ac742",
  "customer_account_id": "4dad42f808",
  "currency": "EUR",
  "order_description": "Premium package",
  "order_items": "item5",
  "order_date": "2025-02-21 11:21:30",
  "order_number": 4,
  "settle_interval": 48,
  "force3ds": true,
  "customer_email": "user-one@mail.com",
  "traffic_source": "Instagram",
  "transaction_source": "Main menu",
  "order_metadata": {
    "coupon_code": "NY2025",
    "partner_id": "123989"
  },
  "success_url": "http://merchant.example/success",
  "fail_url": "http://merchant.example/fail"
}
Subscription 1.0
{
  "product_id": "faf3b86a-1fe6-4ae5-84d4-ab0651d75db2",
  "customer_account_id": "4dad42f808",
  "currency": "EUR",
  "order_description": "Premium package",
  "order_items": "item5",
  "order_date": "2025-02-21 11:21:30",
  "order_number": 4,
  "settle_interval": 48,
  "force3ds": true,
  "customer_email": "user-one@mail.com",
  "traffic_source": "Instagram",
  "transaction_source": "Main menu",
  "order_metadata": {
    "coupon_code": "NY2025",
    "partner_id": "123989"
  },
  "success_url": "http://merchant.example/success",
  "fail_url": "http://merchant.example/fail"
}
Step 1. Form partial intent data

For updating, provide transaction-related information. This information resides in a FormUpdateDTO object, created by invoking the formUpdate function on your API instance.

PHP
<?php

use SolidGate\API\Api;

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

$formUpdateDTO = $api->formUpdate(['JSON payment intent // fill as described in documentation']);
Node.js
const solidGate = require('@solidgate/node-sdk');

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

let partialIntentData = {
    /// fill it as described in documentation
}
let formUpdateDTO = api.formUpdate(partialIntentData);

const dataToFront = formUpdateDTO.toObject()

/// This values should be applied on front end in the following way

const form.update(dataToFront)
Go
package main

import (
    "encoding/json"
    "fmt"

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

type UpdateParams struct {
    ...
}

func main() {
    solidgateSdk := solidgate.NewSolidGateApi("public_key", "secret_key")
    partialIntent := solidgate.PartialIntent{} // fill in the necessary information for updating as described in the documentation
    partialIntentBytes, err := json.Marshal(partialIntent)

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

    formUpdateDto, err := solidgateSdk.FormUpdate(partialIntentBytes)

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

    // ...
}
Kotlin
val api = Api(HttpClient(), Credentials("public_key", "secret_key"))

val attributes = Attributes(mapOf(
    // fill as described in documentation
))

val formUpdateDTO = api.formUpdate(attributes)
Python
from solidgate import ApiClient

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

partial_intent_dict = {} # fill as described in documentation
responseDTO = client.form_update(partial_intent_dict)
Java
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class FormUpdateGenerator {
    private final String publicKey = "api_pk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx";
    private final String secretKey = "api_sk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx";

    public String encryptPartialIntent(String jsonString) 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[] encrypted = cipher.doFinal(jsonString.getBytes(StandardCharsets.UTF_8));
        byte[] withIV = new byte[iv.length + encrypted.length];
        System.arraycopy(iv, 0, withIV, 0, iv.length);
        System.arraycopy(encrypted, 0, withIV, iv.length, encrypted.length);
        return Base64.getEncoder().encodeToString(withIV).replace("+", "-").replace("/", "_");
    }

    public String generateSignature(String jsonString) throws Exception {
        String data = publicKey + jsonString + publicKey;
        Mac mac = Mac.getInstance("HmacSHA512");
        mac.init(new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA512"));
        byte[] hashBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        StringBuilder hexHash = new StringBuilder();
        for (byte b : hashBytes) hexHash.append(String.format("%02x", b & 0xff));
        return Base64.getEncoder().encodeToString(hexHash.toString().getBytes(StandardCharsets.UTF_8));
    }

    public static void main(String[] args) throws Exception {
        FormUpdateGenerator gen = new FormUpdateGenerator();
        String partialIntentJson = "{\"amount\":1020,\"currency\":\"EUR\"}"; // fill as described in documentation
        String partialIntent = gen.encryptPartialIntent(partialIntentJson);
        String signature = gen.generateSignature(partialIntentJson);
        // Pass partialIntent and signature to form.update() on the frontend
        System.out.println("partialIntent: " + partialIntent);
        System.out.println("signature: " + signature);
    }
}
Ruby
require 'openssl'
require 'base64'

class FormUpdateGenerator
  KEY_LENGTH = 32
  IV_LENGTH  = 16

  def initialize
    @public_key = 'api_pk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx'
    @secret_key = 'api_sk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx'
  end

  def encrypt_partial_intent(json_string)
    key    = @secret_key[0, KEY_LENGTH]
    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(json_string) + cipher.final
    Base64.urlsafe_encode64(iv + encrypted).gsub('+', '-').gsub('/', '_')
  end

  def generate_signature(json_string)
    data   = @public_key + json_string + @public_key
    digest = OpenSSL::Digest.new('sha512')
    hmac   = OpenSSL::HMAC.hexdigest(digest, @secret_key, data)
    Base64.strict_encode64(hmac)
  end
end

gen                = FormUpdateGenerator.new
partial_intent_json = '{"amount":1020,"currency":"EUR"}' # fill as described in documentation

partial_intent = gen.encrypt_partial_intent(partial_intent_json)
signature      = gen.generate_signature(partial_intent_json)

# Pass partial_intent and signature to form.update() on the frontend
puts "partialIntent: #{partial_intent}"
puts "signature: #{signature}"
C#
using System;
using System.Security.Cryptography;
using System.Text;

class FormUpdateGenerator
{
    private const string PublicKey = "api_pk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx";
    private const string SecretKey = "api_sk_xxxxaxxxxbdf47a2aea17eb3xxxxxxxx";

    public static string EncryptPartialIntent(string jsonString)
    {
        byte[] iv = new byte[16];
        RandomNumberGenerator.Fill(iv);
        using (var aes = new RijndaelManaged())
        {
            aes.Key     = Encoding.UTF8.GetBytes(SecretKey.Substring(0, 32));
            aes.Mode    = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            using (var encryptor = aes.CreateEncryptor(aes.Key, iv))
            {
                byte[] valueBytes = Encoding.UTF8.GetBytes(jsonString);
                byte[] encrypted  = encryptor.TransformFinalBlock(valueBytes, 0, valueBytes.Length);
                byte[] withIV     = new byte[iv.Length + encrypted.Length];
                Array.Copy(iv,        0, withIV, 0,         iv.Length);
                Array.Copy(encrypted, 0, withIV, iv.Length, encrypted.Length);
                return Convert.ToBase64String(withIV).Replace("+", "-").Replace("/", "_");
            }
        }
    }

    public static string GenerateSignature(string jsonString)
    {
        string data = PublicKey + jsonString + PublicKey;
        using (var hmac = new HMACSHA512(Encoding.UTF8.GetBytes(SecretKey)))
        {
            byte[] hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
            string hexHash   = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
            return Convert.ToBase64String(Encoding.UTF8.GetBytes(hexHash));
        }
    }

    static void Main()
    {
        string partialIntentJson = "{\"amount\":1020,\"currency\":\"EUR\"}"; // fill as described in documentation
        string partialIntent     = EncryptPartialIntent(partialIntentJson);
        string signature         = GenerateSignature(partialIntentJson);
        // Pass partialIntent and signature to form.update() on the frontend
        Console.WriteLine("partialIntent: " + partialIntent);
        Console.WriteLine("signature: "     + signature);
    }
}
Step 2. Pass generated data to frontend

The FormUpdateDTO object, returned by the FormUpdateDTO function, is a class instance. Convert it to a plain object for use in frontend code. This conversion is accomplished by calling the toObject function on the FormUpdateDTO object, resulting in a plain JavaScript object.

After forming the merchant data and converting it to a plain object, use it in frontend code to update with the partialIntent encrypted String

Partial form update

partialIntent string

Description

Encrypted aes-cbc-256 string of JSON request data with random IV (16 bytes) and secret key is the first 32 bytes of the merchant secret key.

Example

E5FKjxw5vRjjIZ....vmG2YFjg5xcvuedQ==

signature string

Description

Signature of request.

It allows verifying whether the request from the Merchant is genuine on the payment gateway server.

Example

MjNiYjVj…ZhYmMxMzNiZDY=

React
import React, { FC, useRef, useCallback, useEffect } from 'react'
import ReactDOM from 'react-dom';
import Payment, { InitConfig, ClientSdkInstance } from "@solidgate/react-sdk"

export const MyPayment: FC<{
  merchantData: InitConfig['merchantData']
  update?: {
    partialIntent: string;
    signature: string;
  }
}> = (props) => {
  const formResolve = useRef<(form: ClientSdkInstance) => void>(() => {})
  const formPromise = useRef<Promise<ClientSdkInstance>>()

  const handleOnReadyPaymentInstance = useCallback((form: ClientSdkInstance) => {
    formResolve.current(form)
  }, [])

  useEffect(() => {
    formPromise.current = new Promise<ClientSdkInstance>((resolve) => {
      formResolve.current = resolve
    })
  }, [])

  useEffect(() => {
    if (props.update && formPromise.current) {
      formPromise.current.then((form) => form
        .update(props.update)
        .then(callbackForSuccessUpdate)
        .catch(callbackForFailedUpdate)
      )
    }
  }, [props.update])

  return (
    <Payment
      merchantData={props.merchantData}
      onReadyPaymentInstance={handleOnReadyPaymentInstance}
  />)
}
JavaScript
form
  .update({ partialIntent, signature })
  .then(callbackForSuccessUpdate)
  .catch(callbackForFailedUpdate);
Vue
<template>
  <Payment
    :merchant-data="merchantData"
      @ready-payment-instance="onReadyPaymentInstance"
  />
</template>

<script lang="ts" setup>
import { defineAsyncComponent } from 'vue'
import { InitConfig, ClientSdkInstance } 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-->>'
}

function onReadyPaymentInstance(form: ClientSdkInstance): void {
  form
      .update({ partialIntent, signature })
      .then(callbackForSuccessUpdate)
      .catch(callbackForFailedUpdate)
}
</script>
Angular
import {Component} from '@angular/core';
import {BehaviorSubject, filter} from 'rxjs'
import {InitConfig, SdkMessage, MessageType} from '@solidgate/angular-sdk';

@Component({
  selector: 'app-root',
  template: `
    <ngx-solid-payment
      [merchantData]="merchantData"
      (readyPaymentInstance)="formSubject$.next($event)"
    ></ngx-solid-payment>
  `
})
export class AppComponent {
  formSubject$ = new BehaviorSubject<ClientSdkInstance | null>(null)

  form$ = this.formSubject$.pipe(filter(Boolean))

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

  update(payload: {
    partialIntent: string;
    signature: string;
  }): void {
    this.form$.subscribe(form => form
      .update(payload)
      .then(callbackForSuccessUpdate)
      .catch(callbackForFailedUpdate))
  }
}
It is very important to handle possible errors, including network errors, in callbackForFailedUpdate by calling a valid update or init. Otherwise, the form remains unresponsive.

If an invalid parameter exists in the updateIntent request, such as a non-unique product_id, an error occurs.

Update Error
{
  "error": {
    "code": "2.01",
    "message": [
      "Invalid Data"
    ]
  }
}

A Billing checkout intent does not update plan, quantity, coupon, or trial through partialIntent and update . Those fields live on the checkout object at init, so the form exposes a separate updateCheckout method instead of the signed formUpdate flow above.

Checkout update

updateCheckout changes line items, discounts, or trial terms on a form initialized with a Billing checkout object. It applies to Subscription 2.0 and Invoice intents that include checkout.mode as subscription or invoice .

The form instance uses camelCase field names. The encrypted paymentIntent uses snake_case for the same checkout data.

Prerequisites

updateCheckout works only on a payment intent created in checkout flow, with a checkout block and mode invoice or subscription .

A one-time payment intent, or an intent paid with product_price_id or invoice_id and no checkout block, fails with Not a checkout flow.
Method call

Call updateCheckout on the form instance returned from PaymentFormSdk.init. Do not send partialIntent or a backend formUpdate signature.

The method always settles the promise it returns. It resolves with the updated invoice preview on success, or rejects with an Error on failure. It does not throw synchronously. Wrap the await call in try/catch.

React
import React, { FC, useRef, useCallback, useEffect } from 'react'
import Payment, { InitConfig, ClientSdkInstance } from "@solidgate/react-sdk"

export const MyPayment: FC<{
  merchantData: InitConfig['merchantData']
  checkoutConfig?: {
    lineItems: Array<{ productPriceId: string; quantity: number; description?: string }>
    discounts?: Array<{ couponId?: string; couponCode?: string }>
  }
}> = (props) => {
  const formResolve = useRef<(form: ClientSdkInstance) => void>(() => {})
  const formPromise = useRef<Promise<ClientSdkInstance>>()

  const handleOnReadyPaymentInstance = useCallback((form: ClientSdkInstance) => {
    formResolve.current(form)
  }, [])

  useEffect(() => {
    formPromise.current = new Promise<ClientSdkInstance>((resolve) => {
      formResolve.current = resolve
    })
  }, [])

  useEffect(() => {
    if (props.checkoutConfig && formPromise.current) {
      formPromise.current.then((form) => form
        .updateCheckout(props.checkoutConfig)
        .then((result) => { /* use result.invoicePreview */ })
        .catch((error) => { /* handle UpdateCheckoutError */ })
      )
    }
  }, [props.checkoutConfig])

  return (
    <Payment
      merchantData={props.merchantData}
      onReadyPaymentInstance={handleOnReadyPaymentInstance}
  />)
}
JavaScript
const form = PaymentFormSdk.init({
  merchantData: { merchant, signature, paymentIntent },
});

try {
  const result = await form.updateCheckout({
    lineItems: [{ productPriceId: "b1e6c2b0-3a4d-4f2e-9b7a-1234567890ab", quantity: 2 }],
    discounts: [{ couponCode: "SUMMER10" }],
  });

  // Success: result.invoicePreview holds the recalculated totals
  console.log(result.invoicePreview.total, result.invoicePreview.currency);
} catch (error) {
  console.error(error);
}
Vue
<template>
  <Payment
    :merchant-data="merchantData"
      @ready-payment-instance="onReadyPaymentInstance"
  />
</template>

<script lang="ts" setup>
import { defineAsyncComponent } from 'vue'
import { InitConfig, ClientSdkInstance } 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-->>'
}

async function onReadyPaymentInstance(form: ClientSdkInstance): Promise<void> {
  try {
    const result = await form.updateCheckout({
      lineItems: [{ productPriceId: 'b1e6c2b0-3a4d-4f2e-9b7a-1234567890ab', quantity: 2 }],
      discounts: [{ couponCode: 'SUMMER10' }],
    })
    // use result.invoicePreview
  } catch (error) {
    // handle UpdateCheckoutError
  }
}
</script>
Angular
import {Component} from '@angular/core';
import {BehaviorSubject, filter} from 'rxjs'
import {InitConfig} from '@solidgate/angular-sdk';

@Component({
  selector: 'app-root',
  template: `
    <ngx-solid-payment
      [merchantData]="merchantData"
      (readyPaymentInstance)="formSubject$.next($event)"
    ></ngx-solid-payment>
  `
})
export class AppComponent {
  formSubject$ = new BehaviorSubject<ClientSdkInstance | null>(null)

  form$ = this.formSubject$.pipe(filter(Boolean))

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

  updateCheckout(checkoutConfig: {
    lineItems: Array<{ productPriceId: string; quantity: number }>;
    discounts?: Array<{ couponCode?: string; couponId?: string }>;
  }): void {
    this.form$.subscribe(form => form
      .updateCheckout(checkoutConfig)
      .then((result) => { /* use result.invoicePreview */ })
      .catch((error) => { /* handle UpdateCheckoutError */ }))
  }
}
Input shape
interface UpdateCheckoutConfig {
  lineItems: UpdateCheckoutLineItem[];
  discounts?: UpdateCheckoutDiscount[];
  subscriptionData?: UpdateCheckoutSubscriptionData;
}

interface UpdateCheckoutLineItem {
  productPriceId: string;
  quantity: number;
  description?: string;
}

interface UpdateCheckoutDiscount {
  couponId?: string;
  couponCode?: string;
}

interface UpdateCheckoutSubscriptionData {
  trial?: {
    type: "free" | "paid";
    period: { value: number; unit: "day" | "week" | "month" };
    amount?: number;
    settleInterval?: number;
  };
  metadata?: Record<string, string>;
  description?: string;
}
lineItems array of objects Required

Description

Full replacement set of line items for the checkout.

Must contain at least one item.
productPriceId string Required

Description

Product price ID charged on this line. The ID must resolve to a product and price known to the merchant.

Example

b1e6c2b0-3a4d-4f2e-9b7a-1234567890ab

quantity integer [1..999999] Required

Description

Quantity for the line item. A positive whole number.

Example

2

description string [1..255]

Description

Free-text description for the line item, shown on the invoice.

Example

Annual plan seats

discounts array of objects [0..1]

Description

Coupon applied to the checkout. Pass at most one discount. For a coupon on a checkout intent, pass discounts here rather than the applyCoupon method.

Provide either couponId or couponCode not both.
couponId string [1..100]

Description

Internal coupon identifier.

Cannot be used together with couponCode.

Example

coup_abc123

couponCode string [2..25]

Description

Customer-facing coupon code. Letters and digits only.

Cannot be used together with couponId.

Example

SUMMER10

subscriptionData object

Description

Subscription configuration. Use only when checkout.mode is subscription .


trial object

Description

Trial terms for the subscription.


type string Required

Description

Whether the trial is free or a paid trial.

Allowed values are free and paid. Required when trial is present.

Example

paid

period object Required

Description

Length of the trial. Required when trial is present.

Maximums are day ≤ 365, week ≤ 52, and month ≤ 12.
value integer Required

Description

Trial duration in units.

Example

7

unit string Required

Description

Trial duration unit.

Allowed values are day, week, and month.

Example

day

amount integer

Description

Trial charge amount. A positive number.

Required when type is paid. Omit when type is free.

Example

199

settleInterval integer [0..240]

Description

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

Required when type is paid. Omit when type is free.

Example

48

metadata object

Description

Free-form key/value metadata attached to the subscription.

At most 10 pairs.

Example

{
  "campaign": "spring_2026",
  "channel": "ads"
}
description string [1..500]

Description

Free-text description for the subscription.

Example

Premium plan annual

Output shape

A successful call resolves with invoicePreview. Amounts are decimal strings, for example “40.00”, not floats, to avoid precision loss.

interface UpdateCheckoutResult {
  invoicePreview: CheckoutInvoicePreview;
}

interface CheckoutInvoicePreview {
  total: string;
  currency: string;
  currencyIcon: string;
  amounts?: {
    subtotal: string;
    discount: string;
    unitPrice?: string;
    taxable?: string;
    tax?: string;
  };
  lineItems: Array<{
    amount: string;
    quantity: number;
    currency: string;
    currencyIcon: string;
    productPriceId: string;
    productId: string;
    amounts?: CheckoutInvoicePreview['amounts'];
    tax?: { categoryId: string; mode: string; rate: number };
  }>;
}
invoicePreview.total string

Description

Total amount due, as a decimal string.

Example

40.00

invoicePreview.currency string

Description

ISO currency code.

Example

USD

invoicePreview.currencyIcon string

Description

Currency symbol for display.

Example

$

invoicePreview.amounts object

Description

Amount breakdown. All values are decimal strings.


subtotal string

Description

Subtotal before discount and tax.

Example

50.00

discount string

Description

Total discount applied.

Example

10.00

unitPrice string

Description

Unit price, when applicable.

Example

25.00

taxable string

Description

Taxable amount, when applicable.

Example

40.00

tax string

Description

Tax amount, when applicable.

Example

0.00

invoicePreview.lineItems array of objects

Description

Per-line-item breakdown. Mirrors the request line items with computed amounts. Currency on each line matches the overall invoice currency.


amount string

Description

Line total.

Example

40.00

quantity integer

Description

Quantity.

Example

2

currency string

Description

ISO currency code for this line.

Example

USD

currencyIcon string

Description

Currency symbol for this line.

Example

$

productPriceId string

Description

Price identifier echoing the request.

Example

b1e6c2b0-3a4d-4f2e-9b7a-1234567890ab

productId string

Description

Product identifier from the catalog.

Example

fa43b415-5522-4373-b026-a365562f9649

amounts object

Description

Same shape as the top-level amounts, scoped to this line.

Example

{
  "subtotal": "50.00",
  "discount": "10.00"
}
tax object

Description

Tax classification and rate applied to this line. Includes categoryId, mode, and rate.

Error handling

When updateCheckout rejects, the caught value is an Error named UpdateCheckoutError. The Error message is a human-readable summary and includes the details payload.

interface UpdateCheckoutError extends Error {
  name: "UpdateCheckoutError";
  message: string;
  details: {
    code: string;
    message: string[] | Record<string, string>;
  };
}

details.message takes one of two shapes, depending on the kind of failure:

  • An array of strings for a request-level failure, for example ["Intent is not payable"] or ["Init payment not found"]. Render these as a general error banner.
  • An object mapping field to message for input that failed validation, for example { "lineItems[0].productPriceId": "must be a valid UUID" }. Render these as per-field hints.

Check which shape details.message is before using it.