Skip to main content

Integration Workflow

This guide provides a step-by-step implementation of the AI Checkout flow. We assume you are building an Agent Runtime using Node.js or TypeScript.

Prerequisites

You will need a Web3 library to handle EIP-712 hashing and signing (if testing server-side) or to request signatures (if client-side).

npm install ethers
# or
npm install viem

The process starts when your Agent identifies a Payment Link ID (e.g., lnk_...).

const getPaymentLink = async (linkId) => {
const response = await fetch(`https://api.gstable.io/payment/link/${linkId}`);
const data = await response.json();
return data;
};

For complete field definitions, refer to API Reference: Get Payment Link

{
"linkId": "lnk_Wch3k5nYWWOvDLFvlwS4tzP6R9rZiQmi",
"linkVersion": "ver_dB54AvbEnFOSuLeA",
"merchantId": "f7d65b193454db46fb2d6277e2f5e593bffcf6adde5064a2bb5dee6fd9b0fb7a",
"aiView": {
"supportedPaymentTokens": [
{
"chainId": "137",
"tokenAddress": "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
"symbol": "USDC",
"amountInToken": "3009000", // 3.009 USDC
"decimals": 6
}
],
"createPaymentSessionRequirement": {
"authorizationRequired": true,
"authorizationSpec": {
"type": "eip712",
"domain": { ... },
"types": { ... }
}
}
}
}

Step 2: Implement Authorization Logic

To create a session, you must generate a signature. We provide a helper class to construct the EIP-712 payload.

Helper Class: PaymentSessionCreationAuthorizationMessage

Copy this class into your project to handle message construction.

class PaymentSessionCreationAuthorizationMessage {
constructor({
linkId,
linkVersion,
merchantId,
payer,
paymentChainId,
paymentToken,
amount,
authorizationNonce,
authorizationExpiresAt,
}) {
this.purpose = 'create_payment_session';
this.linkId = linkId;
this.linkVersion = linkVersion;
this.merchantId = merchantId;
this.payer = payer;
this.paymentChainId = BigInt(paymentChainId);
this.paymentToken = paymentToken;
this.amount = BigInt(amount);
this.authorizationNonce = authorizationNonce;
this.authorizationExpiresAt = BigInt(authorizationExpiresAt);
}

toMessage() {
return {
purpose: this.purpose,
linkId: this.linkId,
linkVersion: this.linkVersion,
merchantId: this.merchantId,
payer: this.payer,
paymentChainId: this.paymentChainId.toString(),
paymentToken: this.paymentToken,
amount: this.amount.toString(),
authorizationNonce: this.authorizationNonce,
authorizationExpiresAt: this.authorizationExpiresAt.toString(),
};
}
}

Step 3: Create Payment Session

Once the user confirms they want to pay (e.g., "Pay with USDC on Polygon"), your Agent constructs the payload and requests a signature.

3.1 Construct the Message

// 1. Generate Nonce & Expiry
const nonce = "0x" + require('crypto').randomBytes(32).toString('hex');
const expiresAt = Math.floor(Date.now() / 1000) + 3600; // 1 hour validity

// 2. Initialize the Helper
const authMsg = new PaymentSessionCreationAuthorizationMessage({
linkId: "lnk_Wch3k5nYWWOvDLFvlwS4tzP6R9rZiQmi",
linkVersion: "ver_dB54AvbEnFOSuLeA", // From Step 1 Response
merchantId: "f7d65b193454db46fb2d6277e2f5e593bffcf6adde5064a2bb5dee6fd9b0fb7a", // From Step 1 Response
payer: "0x123...", // User's Wallet Address
paymentChainId: "137", // User Selection
paymentToken: "0x3c4...", // User Selection
amount: "3009000", // From Step 1 Response (supportedPaymentTokens)
authorizationNonce: nonce,
authorizationExpiresAt: expiresAt
});

3.2 Request User Signature (Client-Side)

If your Agent is running in a browser environment, use the user's provider to sign.

// Using ethers.js v6
const domain = {
name: "aipay.gstable.io",
version: "1",
chainId: 137 // MUST match the paymentChainId
};

const types = {
PaymentSessionCreationAuthorization: [
{ name: "purpose", type: "string" },
{ name: "linkId", type: "string" },
{ name: "merchantId", type: "string" },
{ name: "payer", type: "address" },
{ name: "paymentChainId", type: "uint256" },
{ name: "paymentToken", type: "address" },
{ name: "amount", type: "uint256" },
{ name: "authorizationNonce", type: "bytes32" },
{ name: "authorizationExpiresAt", type: "uint256" }
]
};

// Request signature from wallet
const signature = await signer.signTypedData(domain, types, authMsg.toMessage());

For complete field definitions, refer to API Reference: Create Session

Send the signed payload to create the session.

const createSession = async () => {
const payload = {
message: authMsg.toMessage(),
signature: signature
};

const response = await fetch('https://api.gstable.io/payment/session/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});

return await response.json();
};

Step 4: Prepare & Execute Payment

After creating the session, the workflow proceeds to prepare_payment. This step locks the final transaction details.

Helper Class: PreparePaymentAuthorizationMessage

class PreparePaymentAuthorizationMessage {
constructor({
sessionId,
merchantId,
payer,
payerEmail,
paymentChainId,
paymentToken,
authorizationNonce,
authorizationExpiresAt,
}) {
this.purpose = 'prepare_payment';
this.sessionId = sessionId;
this.merchantId = merchantId;
this.payer = payer;
this.paymentChainId = BigInt(paymentChainId);
this.payerEmail = payerEmail;
this.paymentToken = paymentToken;
this.authorizationNonce = authorizationNonce;
this.authorizationExpiresAt = BigInt(authorizationExpiresAt);
}

toMessage() {
return {
purpose: this.purpose,
sessionId: this.sessionId,
merchantId: this.merchantId,
payer: this.payer,
payerEmail: this.payerEmail,
paymentChainId: this.paymentChainId.toString(),
paymentToken: this.paymentToken,
authorizationNonce: this.authorizationNonce,
authorizationExpiresAt: this.authorizationExpiresAt.toString(),
};
}
}

For complete field definitions, refer to API Reference: Prepare Payment

  1. Construct PreparePaymentAuthorizationMessage using the sessionId returned from Step 3.
  2. Request a second signature from the user.
  3. Call POST /payment/prepare.
  4. The API returns calldata.
  5. Your Agent prompts the user to send the transaction:
// Step 5: Send Transaction
const tx = await signer.sendTransaction({
to: response.data.aiView.paymentExecutionGuide.executionRequest.txRequest.to,
data: response.data.calldata,
value: 0
});
console.log("Transaction sent:", tx.hash);