> For the complete documentation index, see [llms.txt](https://docs.coindpay.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.coindpay.xyz/landing/start/developers/integration.md).

# Integration

CoindPay provides a universal payment experience, enabling businesses to accept and complete payments across websites, mobile apps, e-commerce checkouts, SaaS platforms, and digital portals.

## Environment

### Testnet

`App`  [https://test.coindpay.xyz](https://test.coindpay.xyz/) （ <mark style="background-color:$danger;">Integration & Debugging</mark> ）

Core steps: register merchants, manage payments, bind settlement wallets, configure webhooks, and integrate the merchant order flow end-to-end > [test.coindpay.xyz/account/payouts](https://test.coindpay.xyz/account/payouts)

Subscription-type Payments Links require contacting our team（ [@CoindPay](https://x.com/CoindPay) or collaboration group ）to whitelist static IPs and configure the necessary sandbox permissions.

Other payment types and business scenarios remain publicly available and open by default.

You can check your current IP at [https://whatismyipaddress.com](https://whatismyipaddress.com/)  VPN may affect your outbound IP.

### Prod

`App`  [https://coindpay.xyz](https://coindpay.xyz/) （ <mark style="background-color:$danger;">Production Business & KYB Required</mark> ）

* **Payments** support **USDT/USDC** on **EVM** and **SVM** networks [Pay-ins](/landing/start/customers/pay-ins.md#settlement-payout-assets)\
  Please confirm that your **connected wallet** matches the correct network in your account settings.
* **On/Off-ramps** support **100+ assets** across **30+ networks** for large-volume **buy and sell crypto** transactions. When creating ramp orders, ensure that your selected asset type matches the corresponding wallet address.
* Wallet configuration is fully flexible — developers can specify either an **EVM** or **SVM** address as the payout primary wallet > [coindpay.xyz/account/payouts](https://coindpay.xyz/account/payouts)

## 1. Create Account

Before using CoindPay, you need to create an account. This account serves as a **unified identity** for both your developer role and merchant enterprise.

Visit the CoindPay website and choose one of the account creation methods:

* **Social Account**
  * Supported social login providers (e.g. Google, X, etc.)
* **Wallet**
  * **EVM wallet** (Ethereum-compatible chains)
  * **SVM wallet** (Solana)

> <mark style="background-color:purple;">Note: Even if you sign up using a social account, you will still be required to bind a payout wallet to complete</mark> <mark style="background-color:red;">**and enable payments.**</mark>

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2F5ytfRBndmoPTPxWl4JJS%2Fimage.png?alt=media&amp;token=b0bfe732-edfd-4621-b750-d9cccfdebbf0" alt=""><figcaption></figcaption></figure>

> 💡 Once your account is created, you will have a unified merchant identity to manage Payments Links, track orders, and manage team members.

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2FCcPD9FdYCqEutIFXjrDh%2Fimage.png?alt=media&amp;token=3faa1b4c-c3a9-4796-aa98-6c09c7a2e251" alt=""><figcaption></figcaption></figure>

## 2. Create Payments

A Payments Link is a convenient way to collect payments. You can generate a link and share it with customers or embed it into your applications.

{% hint style="warning" %}
If merchant KYB compliance is not completed, users will be prompted to complete the KYB onboarding and compliance review. The prompt is triggered via **More → Account profile** or during **Pay → Payments create**, with an onboarding modal.
{% endhint %}

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2FXjDFkhPvw3hyaVU0ICWF%2Fimage.png?alt=media&amp;token=fcbf0086-b033-4289-b8d6-da33ac5ecc5c" alt=""><figcaption></figcaption></figure>

#### Option 1: Few Products（No-code）

If you have a small number of products:

1. Create a **Payments Link** and provide the necessary form information at once.
2. Share the link with your customers or embed it in your website/app.

> Designed for no-code integration, for creators or merchants avoiding custom development.

#### Option 2: Many Products（Dynamic）

If you have many products or need dynamic payment links:

1. Create a **Payments Link**&#x20;
2. Dynamically append parameters to generate **unlimited dynamic Payments Links**.
3. Share or embed these links into your applications or product flows.

{% hint style="info" %}

1. All Payments Links support dynamic parameter appending only for the parameters listed in the table below.&#x20;
2. All other settings, such as payment methods, subscription type, and additional options, must be selected and configured directly in the payments form.
   {% endhint %}

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2F6Zlh0WuYep8f7iwO1Qj3%2Fimage.png?alt=media&amp;token=280f1b3a-6d76-4b1a-8c09-7442d98a295a" alt=""><figcaption></figcaption></figure>

## 3. Multiple integrations

### URL Parameters

You can extend the embedded checkout link by appending parameters to the URL.\
This is especially useful when you want to dynamically pass metadata such as product title, description, price, images or others.

<table><thead><tr><th width="224.201171875">Parameter</th><th>Type</th><th width="268.258056640625">Description</th><th width="209.531005859375">Example</th></tr></thead><tbody><tr><td><code>merchant_transaction_id</code></td><td><code>string*</code></td><td><strong>Required.</strong> Unique Id for the order transaction generated by the merchant. Can be generated with <code>randomUUID()</code> to ensure uniqueness. The <code>rampId</code> is returned in webhook order payloads. corresponds to <code>rampId</code></td><td><code>merchant_transaction_id=550e8400-e29b-41d4-a716-446655440000</code></td></tr><tr><td><code>currency</code></td><td><code>string?</code></td><td>Effective only if included in the payment link’s supported currency list; otherwise defaults to the first configured currency.</td><td><code>currency=EUR</code></td></tr><tr><td><code>price</code></td><td><code>string?</code></td><td>Payment amount in the supported fiat or crypto currency format.<br><mark style="background-color:purple;"><strong>Lmimits #</strong></mark><a data-mention href="/landing/start/customers/fiat-currencies.md">Fiat currencies</a></td><td><code>price=29.99</code></td></tr><tr><td><code>signature</code></td><td><code>string?</code></td><td>HMAC-SHA256 hex signature generated with the merchant secret key; <strong>Required</strong> if a custom price is provided.</td><td><code>signature=b95df8938****9fgk56</code></td></tr><tr><td><code>title</code></td><td><code>string?</code></td><td>The product or payment title displayed on the checkout page.</td><td><code>title=Hello</code>  </td></tr><tr><td><code>desc</code></td><td><code>string?</code></td><td>A short description of the product or service.</td><td><code>desc=Text</code></td></tr><tr><td><code>images</code></td><td><code>array?</code></td><td>A list of image objects to display in the checkout interface.</td><td><code>images=[{"url":"https://cdn.example.com/item.jpg"}]</code></td></tr><tr><td><code>name</code></td><td><code>string?</code></td><td>Pre-filled consumer name (≤120 characters)</td><td><code>name=Elon Musk</code></td></tr><tr><td><code>email</code></td><td><code>string?</code></td><td>Pre-fill the customer's email in the checkout form.</td><td><code>email=user@example.com</code></td></tr><tr><td><code>payment_method</code></td><td><code>string?</code></td><td>optional. Fiat payments only. If not specified, all payment methods supported for the selected currency will be returned. If specified, the method will be automatically preselected at checkout.<br>Supported values include <code>card</code>, <code>google</code>, <code>apple</code>, <code>cashapp</code>, <code>revolut_pay</code>, <code>paypal</code>  and others payment methods. Refer to <a data-mention href="/landing/start/customers/payment-methods.md">Payment methods</a> for the full and up-to-date list.</td><td><code>payment_method=cashapp</code></td></tr><tr><td><code>fix_payment_method</code></td><td><code>boolean?</code></td><td>Locks the selected <code>payment_method</code> and prevents changes during checkout. Recommended for channel-specific flows (e.g. iOS) to optimize conversion and payment success.</td><td><code>fix_payment_method=true</code></td></tr><tr><td><code>redirect_url</code></td><td><code>string?</code></td><td>Redirect URL to which the user is redirected after passing the payments or ramps scenes; We recommend using the <strong>default checkout exit flow</strong> rather than redirecting via <code>redirect_url</code>. redirect urls are subject to <strong>risk and compliance monitoring</strong>, and high-risk or non-compliant destinations may affect <strong>merchant account health</strong>.</td><td><code>redirect_url=https://coindpay.xyz/wallet</code></td></tr><tr><td><mark style="background-color:yellow;">more</mark></td><td></td><td>Please contact our Devs team for dynamic updates.</td><td></td></tr></tbody></table>

{% hint style="info" %}

#### **Checkout Tips**

*<mark style="background-color:red;">?</mark> The value is optional, <mark style="background-color:red;">\*</mark> the value is required.*\
Non-authentic product or consumer information, such as `title`, `email`, and `desc`, is not required to be provided.

1. **merchant\_transaction\_id**

* The `merchant_transaction_id` is **required**.
* Orders may transition through multiple statuses, but all remain tied to the same `merchant_transaction_id`
* Separate or recurring orders generate **distinct `merchant_transaction_id`** values.
* Use `randomUUID()`  or other encrypted Id libraries to generate a **unique Id** for each transaction to avoid duplicates.
* `merchant_transaction_id` serves as an alias for `rampId`. The `rampId` is returned in webhook order payloads.
* If not provided, it will **not cause an error**, but you may lose the ability to reliably **track the order** or **query its status** via this Id.

2. **email**

* Ensure the pre-submitted email matches the one used in subsequent order flows.
* The email should be a **user’s email address obtained in advance**.
* If the email is in a valid format, it will be **automatically pre-filled** in the checkout form.
* If unsure, request the user to **manually enter their email** to prevent mismatches.

3. **price**

* When the `price` routing parameter is enabled, configure the product’s **Amount Type** as **Fixed Amount**.
* The **Random Amount** option is intended for tipping or donation scenarios and is **not controlled** by the `price` parameter.
* When `price` is **not provided**, the payment Link will use the amount configured in the merchant dashboard.
* When `price` **is provided in the URL**, it is treated as **dynamic input** and **must be protected by a signature**.
* Any modification to the `price` value without a valid signature will result in the Payment Link being marked as **invalid**.

4. **signature**

* The `signature` parameter is conditionally required.
* f `price` is **present**, a valid `signature` **must** be generated and included.
* If `price` is **absent**, `signature` is optional.
* The signature cryptographically binds the request parameters to the merchant and prevents client-side tampering.

5. **currency**

* The `currency` routing parameter is optional.

* Please ensure the provided `currency` is supported in the payment link currency configuration,  passing an unconfigured currency will be ignored.

* [x] Multiple Fiat Currencies ( **USD-pegged Disabled** )

- The product link resolves to either the **first configured currency** or the **developer-provided `currency` parameter** (must match one of the enabled currencies).
- Client-side currency switching is **disabled**; only the resolved currency is used.

* [x] Multiple Fiat Currencies **( USD-pegged Enabled )**

- The product link resolves to either the **first configured currency** or the **developer-provided `currency` parameter** (must exist in the enabled list).
- End users may freely switch between all enabled currencies.
- Amounts remain **anchored to USD**, with conversions applied automatically using **real-time FX rates**.

6. **USD-pegged**

* **Default:** USD-pegged is **disabled**. the **amount remains uniform** and can be controlled via the `price` parameter.
* When **USD-pegged** is enabled:
  * All selected fiat currencies are automatically **pegged to USD**.
  * Settlement amounts are calculated **in real time** based on current FX rates.
    {% endhint %}

### Code for Checkout

```typescript
import { createHmac } from 'crypto'

export function createHmacSignature(secret: string, data: string): string {
  return createHmac('sha256', secret).update(data).digest('hex')
}
```

{% code lineNumbers="true" %}

```typescript
import { randomUUID } from 'crypto'

const paymentLink = 'xxx'  // The payment link created by the merchant in Step 2

const merchant_transaction_id = randomUUID() || 'Your Custom Order Id'

export interface priceSignaturePayload {
  merchant_transaction_id: string
  price: string
}

export function canonicalizePriceSignaturePath(payload: priceSignaturePayload): string {
  return `merchant_transaction_id=${payload?.merchant_transaction_id}&price=${payload?.price}`
}

// secretKey: The merchant/developer’s API Secret from the dashboard integration webhooks.
const secretKey = YOUR_MERCHANT_API_SECRET

// Merchant payment link signature（If price is included in the URL）
export function signCheckoutPriceSignature(payload: priceSignaturePayload): string {
  const canonical = canonicalizePriceSignaturePath(payload)
  return createHmacSignature(secretKey, canonical)
}

// Render to your dynamic product link params
const paramsData = {
  merchant_transaction_id,  // 'xxx-123456',
  title: 'Your product title', // 
  desc: 'Your product desc',
  price: 19.99,
  signature: 'xxx', // signCheckoutPriceSignature('your price payload')
  email: 'your_customers@domain.com'
})

export function getEncodeCheckoutUrl(
  link: string,
  queryData?: Record<string, any>
): string {
  const url = new URL(link)

  Object.entries(queryData || {}).forEach(([key, value]) => {
    if (value === undefined || value === null) return
    url.searchParams.set(
      key,
      typeof value === 'object' ? JSON.stringify(value) : String(value)
    )
  })

  return url.toString()
}


const url = getEncodeCheckoutUrl(paymentLink, paramsData)

// you can preview this url
console.log('url', url)
```

{% endcode %}

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2FZlSZBzZ6GJMLOMK92uVC%2Fimage.png?alt=media&amp;token=bd164636-9cc1-41d7-851e-94a74a9028be" alt=""><figcaption></figcaption></figure>

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2FrtAryLlblE4U3Me5xLDT%2F2026-08-21%2009.18.18.jpg?alt=media&amp;token=51c1756c-95e7-4951-87da-59d8a92689c9" alt=""><figcaption></figcaption></figure>

<https://coindpay.xyz/pay/link/vVKAsfomepqD0fstx9bdE?name=Jason&email=consumer@coindpay.xyz>\
\ <mark style="background-color:$danger;">Note: the actual checkout URL must include the</mark> <mark style="background-color:$danger;"></mark><mark style="background-color:$danger;">`merchant_transaction_id`</mark> <mark style="background-color:$danger;"></mark><mark style="background-color:$danger;">parameter.</mark>

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2FNSIlUSN4XygK5WNsIj8B%2F20251022003507_rec_-convert.gif?alt=media&amp;token=770a86a3-5bdb-4da1-ac3c-56da38d8dd15" alt=""><figcaption></figcaption></figure>

> Example: Quick payment methods limited to iOS channels

<https://coindpay.xyz/pay/link/vVKAsfomepqD0fstx9bdE?payment_method=apple&fix_payment_method=true><br>

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2FBI6xwiT7U9CRAD1VnooM%2Fimage.png?alt=media&amp;token=5989e0ba-6211-44b3-b14a-8eb012c15af1" alt=""><figcaption></figcaption></figure>

### ① Web

{% hint style="info" %}
E-commerce checkouts, SaaS dashboards, or any web-based payment page.
{% endhint %}

#### 1. Embed via iFrame

> Native HTML styles can be customized as needed.

You can freely customize the surrounding HTML, container styles, and transitions using TailwindCSS or your preferred styling approach.

```typescript
// React component + TailwindCSS

const yourCustomName = '', yourCustomStyle = {}

const onIframeLoad = ()=> {} // If some scenes for iframe loading success

<iframe
  src={url}
  allowFullScreen
  sandbox="allow-scripts allow-same-origin allow-popups allow-forms allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation"
  allow="camera; microphone; geolocation; fullscreen; accelerometer; autoplay; clipboard-write; clipboard-read; payment; gyroscope; encrypted-media; picture-in-picture"
  className={yourCustomName}
  style={yourCustomStyle}
  onLoad={onIframeLoad}
/>
```

#### **2. Redirect to Payment Page**

> Customize your content area (Button, image, etc.) style, redirect or open new tab.

```html
<a href={url} target="_blank">
  Pay with CoindPay
</a>
```

{% hint style="info" %}
**Highlights:**

* ✅ No SDK required
* ✅ Instant integration
* ✅ Dynamic data and ui adaptation
  {% endhint %}

### ② Mobile App

{% hint style="info" %}
iOS / Android / React Native / Flutter apps that need to embed or redirect to a payment flow.
{% endhint %}

#### WebView Embed

```typescript
// React Native example

<WebView source={{ uri: url }} />
```

### White-label Checkout

Personalized parameters such as `payment_method`, `fixed_payment_method` can be used to initialize the frontend checkout experience and directly launch the CoindPay checkout interface, making it well-suited for developer merchants seeking a more native and streamlined checkout experience.

For example, merchants can use these parameters to enable or restrict the checkout experience to specific payment methods, such as **Apple Pay** or **Cash App Pay**, based on their integration requirements.

{% hint style="danger" icon="badge-dollar" %}
**Example:** To display only **Cash App Pay** in the checkout:

*your\_payments\_link?payment\_method=cashapp*
{% endhint %}

<div data-with-frame="true"><figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2Fafrmjt3Z6KdG4DHm2u3J%2Fmoments_swiper_05.jpg?alt=media&amp;token=7f208ad3-2d9a-4383-901f-3adfa9f16752" alt=""><figcaption></figcaption></figure></div>

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2FhMCIiH0fgxXLIMWunrXj%2F20260904164831_rec_-convert.gif?alt=media&amp;token=af6a5899-029d-4dff-94a8-ba9fee4a63de" alt=""><figcaption></figcaption></figure>

### Embedded mode

Whether to enable **Embedded** mode depends on the merchant developer’s integration approach.

**Suitable for iframe embedding**（Enabling embedded mode will hide basic payment link details, including merchant and product information, to provide a cleaner and more seamless embedded checkout experience）

{% hint style="danger" icon="badge-dollar" %}
**Directly opening the final checkout step:** When using Embedded mode, provide the actual consumer’s `email` address as a parameter in the checkout URL. A valid email address is required to automatically open the final checkout step. If the `email` parameter is missing or invalid, the checkout will not skip the email step, and the consumer will be prompted to enter their email address manually.

This information may be required for bank-level AML, fraud prevention, and transaction-frequency checks.

**Example:**  *your\_payments\_link?email=xxxx*
{% endhint %}

<div align="left"><figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2FxMHm9cvUqZMPGO1v0hxB%2Fimage.png?alt=media&amp;token=2553d428-ad7d-4ea8-b8ea-7c616010e626" alt=""><figcaption></figcaption></figure></div>

<div data-with-frame="true"><figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2FN9ZEN2KlWqRqyHJdwwng%2Fimage.png?alt=media&amp;token=37402fb4-8147-433e-a8e6-abd4c672e15a" alt=""><figcaption></figcaption></figure></div>

### Theme & Brand

Customize the checkout theme color, brand logo, and other branding elements.

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2F3xeeYxHihV1igWsfjCoJ%2Fimage.png?alt=media&amp;token=fa96193a-0246-4215-b763-95614649dee0" alt=""><figcaption></figcaption></figure>

## 4. Account & Webhooks

{% hint style="info" %}
Manage your account-related settings, including wallet bindings, event callback URLs, notifications, and developer or merchant information.
{% endhint %}

Go to **More → Account/Payouts** or **Integration/Webhooks** to view and manage your developer information, webhook endpoints, and related configurations.

### Wallet payouts

{% hint style="info" %}
When creating a payment link, merchants will be prompted to link a settlement wallet.&#x20;

This step is required for merchants using fiat pay-in and stablecoin or crypto pay-out flows.
{% endhint %}

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2F4cE4J8pc3zFDpUhAh117%2Fimage.png?alt=media&amp;token=fc5549a4-06c2-4511-bf89-9a3c96b10de2" alt=""><figcaption></figcaption></figure>

### Webhooks callback

Once your **Webhooks** are configured under **Developer Settings → Webhooks URLs**, CoindPay will automatically send webhook notifications to your specified endpoint whenever a payment event occurs (e.g., `completed`, `failed`, or `pending`).

Your server should handle these events, verify the request signature using your `API Secret` and update your own order database accordingly.

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2FTUTYYMojwd7CrHJIWTus%2Fimage.png?alt=media&amp;token=e71fa761-728e-4388-8c03-ba1684fbf714" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
The following example code how to handle webhook order data in a `Next.js` API route.

⚠️  Merchants and developers should pay special attention to verifying the `x-signature` request header and securely managing the private `API Secret` found in your **Developer Webhooks** settings.

⚠️  The `API Secret` is used to validate the callback signature. When a transaction status changes, CoindPay sends a webhook request containing the transaction data.\
If you’re using callbacks, make sure to enable signature verification to ensure authenticity.

⚠️  To verify the signature, generate an HMAC SHA-256 hash using your `API Secret` and the **entire raw callback body** as input. Because the signature is generated based on the full payload, the request body must be used **exactly as received**, without any modification or parsing before signature verification.

⚠️  To avoid compatibility issues caused by data serialization differences across programming languages, please pay attention to how `rawBody` is handled in environments such as Node.js, Go, and Java.

⚠️  Before using webhooks and managing the order flow, ensure that your API secret has been generated and that it is correctly applied to the signature headers.
{% endhint %}

#### Local Debugging Mode

{% hint style="info" %}
If you are unable to open the checkout page due to network or connectivity issues, we also provide a **local debugging mode**. This allows you to effectively validate your **webhook api integration** and end-to-end **order flow**.
{% endhint %}

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2FxFpugzPdQqm1oRMX3Xt8%2F20260309172410_rec_.gif?alt=media&amp;token=9174483e-7ebb-4178-8958-c8f39f75fd56" alt=""><figcaption></figcaption></figure>

> #### Below is a webhook API example based on <mark style="background-color:red;">Node (Next.js)</mark>
>
> <mark style="background-color:$primary;">Some code references</mark>[#code-with-parameters](#code-with-parameters "mention")

```typescript
// The unique ID from your front-end with the customers
const merchant_transaction_id = 'xxx' // See => Example with Parameters

// https://api.yourdomain.com/webhooks/payments/landing
import type { NextApiRequest, NextApiResponse } from 'next'
import getRawBody from 'raw-body'

// Refer to the utils code in the “Code with Parameters” ⬆️
import { createSignature } from '@/lib/utils' 

export const config = {
  api: {
    bodyParser: false, // ✅ Disable Next.js automatic body parsing
  },
}

export default async function landing(req: NextApiRequest, res: NextApiResponse) {
  if (req.method !== 'POST') {
    return res.status(405).json({ ok: false, message: 'Method not allowed ˙◠˙' })
  }
  
  try {
    const secretKey = process.env.COINDPAY_API_SECRET_KEY as string
    
    if (!secretKey) {
      throw new Error('Missing CoindPay API SECRET KEY in env ˙◠˙')
    }

    const signatureHeader = req.headers['x-signature'] as string

    if (!signatureHeader) {
      return res.status(400).json({
        ok: false,
        message: 'Invalid signature ˙◠˙',
      })
    }
    
    // 1. Retrieve the raw request body
    const rawBody = (await getRawBody(req)).toString('utf8')
    console.log('📦 raw body:', rawBody)
    
    // 2. Verify signature (must use rawBody for verification)
    const expectedSig = createSignature(secretKey, rawBody)

    if (signatureHeader !== expectedSig) {
      console.error(`🚫 x-signature mismatch:`, { expectedSig, got: signatureHeader })
      return res.status(401).json({ ok: false, message: 'Invalid signature ˙◠˙' })
    }
    
    // 3. Parse JSON payload after successful verification
    const data = JSON.parse(rawBody)
    console.log('💎 Parsed data:', data)
  
    if (!data || !data?.id) {
      return res.status(502).json({ ok: false, message: 'Invalid payment order ˙◠˙' })
    }
    
    console.log(`✅ CoindPay payment ${data?.id}-${data?.rampStatus} callback data：`, data)
    
    // post your order data to your db, create or poll for updates
    // const payment = await prisma.payment.upsert({
    //  where: { rampId: data.id },
    //  update: {
    //    ...data,
    //  },
    //  create: {
    //    ...data,
    //  },
    // })
    ....
  } catch (error) {
    console.error(`🚫 CoindPay order data storage failed:`, error?.message)
  }
}
```

> #### Webhooks Data Example（Selected statuses）[Full Order Fields](/landing/start/developers/payments-order.md#full-order-fields)

{% tabs %}
{% tab title="new" %}

```json
{
    "id": "69ae9bd******0de524430c",
    "createdAt": "2026-03-09T10:07:18.900Z",
    "updatedAt": "2026-03-09T10:07:40.021Z",
    "rampId": "SS2654******96s121",
    "rampStatus": "new",
    "rampType": "pay",
    "payMethod": "mobile_pay",
    "name": "andrew tim",
    "email": "hello@hotmail.com",
    "timezone": "Australia/Adelaide",
    "chain": "BSC",
    "amount": 14.147862,
    "usd": 15,
    "fiatAmount": 15,
    "fiatCoin": "USD",
    "symbol": "USDT",
    "payeeId": "-m3NiJQWM***F8Ih8K6IE",
    "appid": "693a61c42******e914fe691"
}
```

{% endtab %}

{% tab title="pending" %}

```json
{  
    "id": "69ae9bd******0de524430c",
    "createdAt": "2026-03-09T10:07:18.900Z",
    "updatedAt": "2026-03-09T10:07:44.932Z",
    "rampId": "SS2654******96s121",
    "rampStatus": "pending",
    "rampType": "pay",
    "payMethod": "google",
    "name": "andrew tim",
    "email": "hello@hotmail.com",
    "timezone": "Australia/Adelaide",
    "chain": "BSC",
    "amount": 14.147862,
    "usd": 15,
    "fiatAmount": 15,
    "fiatCoin": "USD",
    "symbol": "USDT",
    "payeeId": "-m3NiJQWM***F8Ih8K6IE",
    "appid": "693a61c42******e914fe691"
}
```

{% endtab %}

{% tab title="paid" %}

```json
{
    "id": "69ae9bd78974110de524430c",
    "createdAt": "2026-03-09T10:07:18.900Z",
    "updatedAt": "2026-03-09T10:08:10.242Z",
    "rampId": "SS2654******96s121",
    "rampStatus": "paid",
    "rampType": "pay",
    "payMethod": "google",
    "name": "andrew tim",
    "email": "hello@hotmail.com",
    "timezone": "Australia/Adelaide",
    "chain": "BSC",
    "amount": 14.147862,
    "usd": 15,
    "fiatAmount": 15,
    "fiatCoin": "USD",
    "symbol": "USDT",
    "payeeId": "-m3NiJQWM***F8Ih8K6IE",
    "appid": "693a61c42******e914fe691"
}
```

{% endtab %}

{% tab title="order\_scheduled" %}

```json
{
    "id": "69ae9bd******0de524430c",
    "createdAt": "2026-03-09T10:07:18.900Z",
    "updatedAt": "2026-03-09T10:08:09.065Z",
    "rampId": "SS2654******96s121",
    "rampStatus": "order_scheduled",
    "rampType": "pay",
    "payMethod": "google",
    "name": "andrew tim",
    "email": "hello@hotmail.com",
    "timezone": "Australia/Adelaide",
    "chain": "BSC",
    "amount": 14.147862,
    "usd": 15,
    "fiatAmount": 15,
    "fiatCoin": "USD",
    "symbol": "USDT",
    "payeeId": "-m3NiJQWM***F8Ih8K6IE",
    "appid": "693a61c42******e914fe691"
}
```

{% endtab %}

{% tab title="completed" %}

```json
{
    "id": "69ae9bd******0de524430c",
    "createdAt": "2026-03-09T10:07:18.900Z",
    "updatedAt": "2026-03-09T10:08:54.815Z",
    "settledAt": "2026-03-09T10:08:54.751Z",
    "rampId": "SS2654******96s121",
    "rampStatus": "completed",
    "rampType": "pay",
    "payer": "0x301D477Ec915B46C5561158Df1b5757A6CE22133",
    "payMethod": "google",
    "name": "andrew tim",
    "email": "hello@hotmail.com",
    "timezone": "Australia/Adelaide",
    "chain": "BSC",
    "amount": 14.147862,
    "reserveAmount": 0.707393,
    "afterReserveAmount": 13.440469,
    "usd": 15,
    "fiatAmount": 15,
    "fiatCoin": "USD",
    "symbol": "USDT",
    "signature": "0xbd3f0e2a255b43301b5b8dc02ff3a953be4939c682e98ba4ceeff553bc055590",
    "payeeId": "-m3NiJQWM***F8Ih8K6IE",
    "appid": "693a61c42******e914fe691"
}
```

{% endtab %}

{% tab title="fialed" %}

```json
{
    "id": "69ae9bd******0de524430c",
    "createdAt": "2026-03-09T10:07:18.900Z",
    "updatedAt": "2026-03-09T10:08:50.815Z",
    "rampId": "SS2654******96s121",
    "rampStatus": "failed",
    "rampType": "pay",
    "payMethod": "google",
    "name": "andrew tim",
    "email": "hello@hotmail.com",
    "timezone": "Australia/Adelaide",
    "chain": "BSC",
    "amount": 14.147862,
    "usd": 15,
    "fiatAmount": 15,
    "fiatCoin": "USD",
    "symbol": "USDT",
    "payeeId": "-m3NiJQWM***F8Ih8K6IE",
    "appid": "693a61c42******e914fe691"
}
```

{% endtab %}
{% endtabs %}

### Order status

#### Payments/On-Ramps Status Reference

> Below is a list of possible `rampStatus` values returned&#x20;
>
> when rampType=`buy` paymentMethod=[Payment methods](/landing/start/customers/payment-methods.md)

<table><thead><tr><th width="165.48046875">Status</th><th>Description</th></tr></thead><tbody><tr><td><code>init</code></td><td>The customer has opened the payment window, but has not yet entered the payment flow. The order has not started processing.</td></tr><tr><td><code>new</code></td><td>The order has been created and is ready for payment. <br>Starting from <code>new</code>, merchants with configured webhooks will receive order status notifications.</td></tr><tr><td><code>pending</code></td><td>The order is waiting for a required customer or payment-provider action, such as 3DS authentication or additional verification.</td></tr><tr><td><code>paid</code></td><td>The payment has been authorized and the funds have been received into the payment processing flow. <br>Final settlement and conversion may still be subject to payment-provider, banking, compliance, and eligibility checks.</td></tr><tr><td><code>confirming</code></td><td>The payment has entered the execution and confirmation stage. The transaction may be undergoing payment confirmation, asset conversion, cross-chain routing, or delivery to the configured settlement destination.</td></tr><tr><td><code>order_scheduled</code></td><td>The order has been accepted and placed into the processing queue. This status indicates that processing has been scheduled; it does not indicate that funds have been reserved or settled.</td></tr><tr><td><code>order_retry</code></td><td>The order was declined or cancelled due to <strong>legal, compliance, or banking constraints</strong>. The consumer attempts the payment again through <strong>an alternative recommended banking provider</strong>.</td></tr><tr><td><code>expired</code></td><td>The order was created but the customer did not complete the required payment within the applicable payment window. Expiry times may vary by payment method. An expired order may become active again if a valid payment is subsequently received.</td></tr><tr><td><code>cancelled</code></td><td>The order has been cancelled and will not continue through the normal processing flow. Cancellation may result from customer action, timeout, or an explicit cancellation by CoindPay or an upstream provider.</td></tr><tr><td><code>refunded</code></td><td>The payment has been refunded. The refund was initiated in response to a customer request or as part of the applicable payment or settlement process.</td></tr><tr><td><code>failed</code></td><td>The transaction could not be completed due to a non-recoverable rejection or failure, such as a bank decline, provider rejection, compliance restriction, or other terminal processing error.</td></tr><tr><td><code>settling</code></td><td>The payment has been authorized and the settlement process is in progress. The corresponding payout or on-chain settlement transaction has not yet reached its final state.</td></tr><tr><td><code>settle_failed</code></td><td>Settlement attempt failed due to a transient or recoverable error. The order is eligible for retry（caused by RPC, network, or temporary infrastructure issues, retry may be triggered）</td></tr><tr><td><code>completed</code></td><td>✅ The order has completed successfully and the merchant has received the expected settlement. This is the final successful status and should be treated as the definitive indication that the order has completed.</td></tr></tbody></table>

> #### Status Notes

1. Merchants can use `completed` as the **only status that triggers fulfillment** of goods or services.
2. A `failed` status is reversible while the checkout remains open. The customer can enter `order_retry` and then start a new payment flow from `new`

#### Off-Ramp Status Reference

> Below is a list of possible `rampStatus` values returned&#x20;
>
> when rampType=`sell` paymentMethod=`card`

| Status      | Description                                                                                                                                                    |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `init`      | User opened the payment window but hasn’t entered the payment stage and the order has not yet entered the processing flow.                                     |
| `new`       | <p>A new transaction has been created. <br>Starting from the <code>new</code> status, merchants with configured webhooks will receive event notifications.</p> |
| `pending`   | The transaction is in progress; payout processing has started.                                                                                                 |
| `failed`    | The transaction failed; the crypto amount will be returned to the user.                                                                                        |
| `completed` | ✅ The payout has been successfully transferred to the user’s card.                                                                                             |

💡 **Tips:**

1. Keeping your secret key safe, don't forget add the `.env` file to `.gitignore`
2. The <mark style="background-color:red;">rampId</mark> is required, from your front-end `merchant_transaction_id`
3. An order is successful only when its status is `completed`&#x20;

### Testnet config

> #### <mark style="background-color:purple;">Testnet Provider A</mark> <a href="#sandbox-payment-card-details" id="sandbox-payment-card-details"></a>

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2FrtAryLlblE4U3Me5xLDT%2F2026-08-21%2009.18.18.jpg?alt=media&amp;token=51c1756c-95e7-4951-87da-59d8a92689c9" alt=""><figcaption></figcaption></figure>

Select the test card and verify the payment method at the checkout.

> #### <mark style="background-color:orange;">Order Fallback Testnet Provider B - card list</mark> <a href="#sandbox-payment-card-details" id="sandbox-payment-card-details"></a>

Payout Asset：from your payment link configuration.

**🆔 KYC Data**

A first time customer will be guided through a KYC process during their first order with us. We suggested you input words and names that exist as opposed to random strings, as there are still some basic validations in place.

You may also be asked to upload Id documents. This can be any image with some text, captured using your device. This will not be verified, however will need to be in high resolution.

<figure><img src="https://4241769897-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSH3Edva2xmXt469sOUlR%2Fuploads%2F2gHp9U3R0mH5Ei2aHZgA%2Fimage.png?alt=media&amp;token=fb83d115-2462-4814-8466-6757ec6f32b2" alt=""><figcaption></figcaption></figure>

**Card #1**

| Field         | Value                                         |
| ------------- | --------------------------------------------- |
| Card Name     | Use the name that you provided as part of KYC |
| Card Number   | 4111 1111 1111 1111                           |
| Expiry        | Any expiry date in the future                 |
| Security Code | Any                                           |

### <mark style="background-color:red;">Demo video（Payments）</mark>

{% file src="/files/ckFjq4sRV5naX9Bba90N" %}
