Skip to main content

Create Payment Intent

Creates a new payment intent. A payment intent represents a request to collect payment from a payer.

Endpoint

POST /payment-intents

Authentication

Requires API key authentication.

Request

Parameters

ParameterTypeRequiredDescription
amountstringYesPayment amount (e.g., "100.00")
currencystringYesCurrency code (USDC, USDT, DAI)
typestringYesPayment type (CONDITIONAL, DELIVERY_VS_PAYMENT)
settlementMethodstringYesSettlement method (OFF_RAMP_MOCK, OFF_RAMP_TO_RTP, OFF_RAMP_TO_BANK)
settlementDestinationstringYesWhere to send fiat funds (bank account, RTP ID, etc.)
descriptionstringNoHuman-readable description
metadataobjectNoCustom metadata (key-value pairs)

Escrow-Specific Parameters (for DELIVERY_VS_PAYMENT)

ParameterTypeRequiredDescription
deliveryPeriodnumberNoDelivery period in seconds (default: 2592000 = 30 days)
expectedDeliveryHashstringNoExpected delivery hash (bytes32)
autoReleasebooleanNoAuto-release on delivery proof (default: false)
deliveryOraclestringNoDelivery oracle address (optional)

Metadata Fields for Release Types

For DELIVERY_VS_PAYMENT type, include release type in metadata:

Time-Locked Release:

{
"metadata": {
"releaseType": "TIME_LOCKED",
"timeLockUntil": "1735689600"
}
}

Milestone-Based Release:

{
"metadata": {
"releaseType": "MILESTONE_LOCKED"
}
}

Delivery Proof Release:

{
"metadata": {
"releaseType": "DELIVERY_PROOF",
"autoRelease": true
}
}

Example Request

Delivery vs Payment (Time-Locked)

curl https://sandbox.pg.api.finternetlab.io/v1/payment-intents \
-H "X-API-Key: sk_test_your_key" \
-H "Content-Type: application/json" \
-X POST \
-d '{
"amount": "1000.00",
"currency": "USDC",
"type": "DELIVERY_VS_PAYMENT",
"settlementMethod": "OFF_RAMP_MOCK",
"settlementDestination": "bank_account_123",
"deliveryPeriod": 2592000,
"autoRelease": true,
"metadata": {
"releaseType": "TIME_LOCKED",
"timeLockUntil": "1735689600"
}
}'

Response

Success Response (200 OK)

Returns a payment intent object wrapped in the standard API response format. The response includes a paymentUrl field that you can redirect users to for payment completion.

{
"id": "intent_2xYz9AbC123",
"object": "payment_intent",
"status": "INITIATED",
"data": {
"id": "intent_2xYz9AbC123",
"object": "payment_intent",
"status": "INITIATED",
"amount": "1000.00",
"currency": "USDC",
"type": "DELIVERY_VS_PAYMENT",
"description": "Order #12345",
"settlementMethod": "OFF_RAMP_MOCK",
"settlementDestination": "bank_account_123",
"settlementStatus": null,
"contractAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f42318",
"transactionHash": null,
"chainId": 11155111,
"typedData": {
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"DeliveryVsPayment": [
{ "name": "intentId", "type": "string" },
{ "name": "payer", "type": "address" },
{ "name": "payee", "type": "address" },
{ "name": "amount", "type": "uint256" },
{ "name": "token", "type": "address" },
{ "name": "deadline", "type": "uint256" }
]
},
"domain": {
"name": "DeliveryVsPayment",
"version": "1",
"chainId": 11155111,
"verifyingContract": "0x742d35Cc6634C0532925a3b844Bc9e7595f42318"
},
"message": {
"intentId": "intent_2xYz9AbC123",
"payer": "0x0000000000000000000000000000000000000000",
"payee": "0xMerchantAddress...",
"amount": "1000000000",
"token": "0xTokenAddress...",
"deadline": 1704153600
}
},
"signature": null,
"signerAddress": null,
"phases": [
{
"phase": "SIGNATURE_VERIFICATION",
"status": "IN_PROGRESS"
}
],
"metadata": {
"orderId": "ORD-123",
"customerId": "CUST-456"
},
"paymentUrl": "https://pay.fmm.finternetlab.io/?intent=intent_2xYz9AbC123",
"created": 1704067200,
"updated": 1704067200
},
"metadata": {
"orderId": "ORD-123",
"customerId": "CUST-456"
},
"created": 1704067200,
"updated": 1704067200
}

Frontend Payment URL

Important: The response includes a paymentUrl in the data object. This URL is automatically generated and points to the frontend payment interface where users can:

  1. Connect their wallet
  2. Review payment details
  3. Sign and execute the payment transaction

Example:

{
"data": {
"paymentUrl": "https://pay.fmm.finternetlab.io/?intent=intent_2xYz9AbC123"
}
}

Usage:

const response = await apiRequest('/payment-intents', {...});
const paymentUrl = response.data.paymentUrl;

// Redirect user to payment page
window.location.href = paymentUrl;
// or
window.open(paymentUrl, '_blank');

The payment URL format is:

https://pay.fmm.finternetlab.io/?intent={intentId}

For local development:

http://localhost:5173/?intent={intentId}

Error Responses

Invalid Amount (400)

{
"error": {
"code": "invalid_request_error",
"message": "Amount must be a positive number",
"type": "invalid_request_error"
}
}

Invalid Payment Type (400)

{
"error": {
"code": "invalid_request_error",
"message": "Invalid payment type. Must be CONDITIONAL or DELIVERY_VS_PAYMENT",
"type": "invalid_request_error"
}
}

Authentication Error (401)

{
"error": {
"code": "authentication_required",
"message": "API key is required",
"type": "authentication_error"
}
}

Response Structure

The response follows the standard API response format:

{
id: string; // Payment intent ID
object: "payment_intent"; // Object type
status: string; // Current status (INITIATED)
data: { // Payment intent data object
id: string;
object: "payment_intent";
status: string;
amount: string;
currency: string;
type: string;
description?: string;
settlementMethod: string;
settlementDestination: string;
settlementStatus?: string | null;
contractAddress?: string | null;
transactionHash?: string | null;
chainId?: number | null;
typedData?: object | null; // EIP-712 typed data for signature
signature?: string | null;
signerAddress?: string | null;
phases?: Array<{ // Payment phases
phase: string;
status: string;
timestamp?: number;
}> | null;
metadata?: Record<string, unknown> | null;
paymentUrl: string; // ⭐ Frontend payment URL
created: number; // Unix timestamp
updated: number; // Unix timestamp
};
metadata?: Record<string, unknown>; // Request metadata (echoed back)
created: number; // Unix timestamp
updated: number; // Unix timestamp
}

Key Response Fields

FieldLocationTypeDescription
idTop levelstringUnique payment intent identifier
objectTop levelstringAlways "payment_intent"
statusTop levelstringCurrent payment status
dataTop levelobjectComplete payment intent data
paymentUrldata.paymentUrlstringFrontend URL for payment completion
typedDatadata.typedDataobjectEIP-712 typed data for signature
phasesdata.phasesarrayPayment phases and their statuses
contractAddressdata.contractAddressstringSmart contract address
createdTop level & datanumberUnix timestamp of creation
updatedTop level & datanumberUnix timestamp of last update

Notes

  • Payment intents are created with status INITIATED
  • The paymentUrl is automatically generated and included in data.paymentUrl
  • Redirect users to data.paymentUrl to complete payment on the frontend
  • EIP-712 typed data is included in data.typedData for payer signature
  • For DELIVERY_VS_PAYMENT type, an escrow order is created automatically
  • Metadata is stored and returned in all subsequent requests
  • The paymentUrl format: https://pay.fmm.finternetlab.io/?intent={intentId}

Using the Payment URL

After creating a payment intent, redirect your users to the paymentUrl:

JavaScript/TypeScript

const response = await apiRequest('/payment-intents', {
method: 'POST',
body: JSON.stringify({
amount: '1000.00',
currency: 'USDC',
type: 'CONDITIONAL',
settlementMethod: 'OFF_RAMP_MOCK',
settlementDestination: 'bank_account_123',
}),
});

// Get the payment URL from the response
const paymentUrl = response.data.paymentUrl;

// Redirect user to payment page
window.location.href = paymentUrl;

Python

response = api_request('/payment-intents', method='POST', data={
'amount': '1000.00',
'currency': 'USDC',
'type': 'CONDITIONAL',
'settlementMethod': 'OFF_RAMP_MOCK',
'settlementDestination': 'bank_account_123',
})

payment_url = response['data']['paymentUrl']

# Redirect user (in web framework)
return redirect(payment_url)

Backend Redirect

// Express.js example
app.post('/create-payment', async (req, res) => {
const intent = await createPaymentIntent(req.body);
res.redirect(intent.data.paymentUrl);
});