Skip to main content

Your First Payment

This guide walks you through creating and processing your first payment with Finternet, from creation to settlement.

Sandbox Environment

๐Ÿงช Testing Environment: All examples in this guide use the sandbox environment (api.fmm.finternetlab.io).

๐Ÿš€ Production API will be available once deployed.

Overviewโ€‹

We'll create a simple payment intent, confirm it, and track it through the complete lifecycle. This example uses a Conditional Payment type, which is the simplest payment flow.

Step 1: Create a Payment Intentโ€‹

A payment intent represents a request to collect payment from a payer. Let's create one:

curl https://api.fmm.finternetlab.io/v1/payment-intents \
-H "X-API-Key: sk_test_your_key_here" \
-H "Content-Type: application/json" \
-X POST \
-d '{
"amount": "100.00",
"currency": "USDC",
"type": "CONDITIONAL",
"settlementMethod": "OFF_RAMP_MOCK",
"settlementDestination": "bank_account_123",
"description": "Order #12345"
}'

Response:

{
"id": "intent_2xYz9AbC123",
"object": "payment_intent",
"status": "INITIATED",
"data": {
"id": "intent_2xYz9AbC123",
"object": "payment_intent",
"status": "INITIATED",
"amount": "100.00",
"currency": "USDC",
"type": "CONDITIONAL",
"settlementMethod": "OFF_RAMP_MOCK",
"settlementDestination": "bank_account_123",
"paymentUrl": "https://pay.fmm.finternetlab.io/?intent=intent_2xYz9AbC123",
"contractAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f42318",
"typedData": {
"types": {
"EIP712Domain": [...],
"ConditionalPayment": [...]
},
"domain": {...},
"message": {...}
},
"phases": [
{
"phase": "SIGNATURE_VERIFICATION",
"status": "IN_PROGRESS"
}
],
"created": 1704067200,
"updated": 1704067200
},
"created": 1704067200,
"updated": 1704067200
}

What Happened?โ€‹

  1. โœ… Payment intent created with status INITIATED
  2. โœ… Frontend payment URL generated - Available in data.paymentUrl
  3. โœ… EIP-712 typed data generated for signature
  4. โœ… Contract address assigned

Using the Payment URLโ€‹

Important: The response includes a paymentUrl in the data object. This is the URL where your users should complete the payment.

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

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

The payment URL format is: https://pay.fmm.finternetlab.io/?intent={intentId}

Step 2: Redirect User to Payment Pageโ€‹

After creating the payment intent, redirect your user to the paymentUrl:

// After creating payment intent
const intent = await createPaymentIntent({...});

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

Step 3: Payer Completes Paymentโ€‹

The payer visits the paymentUrl and:

  1. Connects their wallet (MetaMask, WalletConnect, etc.)
  2. Reviews payment details
  3. Signs the EIP-712 message
  4. Executes the blockchain transaction

Note: This step happens on the frontend. The payer's wallet executes the transaction directly on the blockchain. The frontend will automatically call the API to update the transaction hash.

Step 4: Confirm the Paymentโ€‹

Once the payer has executed the transaction, confirm it with the signature and transaction hash:

curl https://api.fmm.finternetlab.io/v1/payment-intents/intent_2xYz9AbC123/confirm \
-H "X-API-Key: sk_test_your_key_here" \
-H "Content-Type: application/json" \
-X POST \
-d '{
"signature": "0x1234567890abcdef...",
"payerAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f42318"
}'

Response:

{
"id": "intent_2xYz9AbC123",
"object": "payment_intent",
"status": "PROCESSING",
"transactionHash": "0xabc123def456...",
"phases": [
{
"phase": "SIGNATURE_VERIFICATION",
"status": "COMPLETED"
},
{
"phase": "BLOCKCHAIN_CONFIRMATION",
"status": "IN_PROGRESS"
}
],
"updated": 1704067250
}

What Happened?โ€‹

  1. โœ… Signature verified
  2. โœ… Transaction submitted to blockchain
  3. โœ… Status updated to PROCESSING
  4. โœ… Blockchain confirmation phase started

Step 5: Check Payment Statusโ€‹

Poll the payment intent to track blockchain confirmation:

curl https://api.fmm.finternetlab.io/v1/payment-intents/intent_2xYz9AbC123 \
-H "X-API-Key: sk_test_your_key_here"

After 5+ confirmations:

{
"id": "intent_2xYz9AbC123",
"object": "payment_intent",
"status": "SUCCEEDED",
"transactionHash": "0xabc123def456...",
"settlementStatus": "IN_PROGRESS",
"phases": [
{
"phase": "BLOCKCHAIN_CONFIRMATION",
"status": "COMPLETED"
},
{
"phase": "SETTLEMENT",
"status": "IN_PROGRESS"
}
],
"updated": 1704067300
}

What Happened?โ€‹

  1. โœ… Blockchain transaction confirmed (5+ blocks)
  2. โœ… Status updated to SUCCEEDED
  3. โœ… Settlement process initiated
  4. โœ… Merchant account credited

Step 6: Settlement Completesโ€‹

Settlement happens automatically in the background. Check status again:

curl https://api.fmm.finternetlab.io/v1/payment-intents/intent_2xYz9AbC123 \
-H "X-API-Key: sk_test_your_key_here"

After settlement:

{
"id": "intent_2xYz9AbC123",
"object": "payment_intent",
"status": "SETTLED",
"settlementStatus": "COMPLETED",
"phases": [
{
"phase": "SETTLEMENT",
"status": "COMPLETED"
}
],
"updated": 1704067400
}

What Happened?โ€‹

  1. โœ… Funds converted from crypto to fiat
  2. โœ… Funds sent to merchant's bank account
  3. โœ… Status updated to SETTLED
  4. โœ… Payment complete!

Complete Flow Diagramโ€‹

flowchart TD
A[Create Intent<br/>Get paymentUrl] -->|INITIATED| B[Redirect user to paymentUrl]
B --> C[Payer signs transaction<br/>on frontend]
C -->|PROCESSING| D[Confirm payment<br/>(auto or manual)]
D -->|SUCCEEDED| E[Blockchain confirmations (5+)]
E -->|SETTLED| F[Settlement completed]

Next Stepsโ€‹

Common Questionsโ€‹

Q: How long does settlement take?
A: Settlement typically completes within 10-30 seconds for mock settlements. Real bank settlements may take 1-3 business days.

Q: What if the transaction fails?
A: If the blockchain transaction fails, the payment intent status will be REQUIRES_ACTION and you can retry.

Q: Can I cancel a payment?
A: Yes, you can cancel a payment intent in INITIATED or REQUIRES_SIGNATURE status.

Q: How do I handle errors?
A: Check the Error Handling guide for all error codes and how to handle them.