Skip to main content

Payment Links

Payment links are shareable URLs that open a hosted checkout page. Create a link, share it via email, social media, or embed it in a button — and customers can pay without you building any checkout UI.
POST /api/v1/payment-links
amount
number
required
Payment amount.
currency
string
default:"USD"
Currency code: USD, EUR, GBP.
token
string
default:"USDC"
Token to accept: USDC, USDT, SOL.
description
string
Description shown on the checkout page.
max_uses
integer
Maximum number of times this link can be used. Omit for unlimited.
expires_at
string
ISO 8601 expiration date for the link itself.
metadata
object
Arbitrary key-value pairs.
onramp
boolean
default:"false"
Enable fiat onramp (NGN to USDC) for this link. The checkout page will present a Pay with Bank option powered by the PAJ Ramp flow.
amount_ngn
number
Original NGN amount for exact PAJ conversion. Bypasses a live FX re-quote at checkout time. Only relevant when onramp is true.
payer_service_charge
boolean
default:"false"
When true (and onramp is true), a transparent service charge — max(₦30, ceil(amount_ngn × 2.5%)) — is added on top and billed to the payer rather than absorbed by the merchant.
collect_customer_info
boolean
default:"false"
When true, the checkout shows an expanded form to collect customer details (name, phone, company, billing address) before the payment step.
customer
CustomerObject
Optional pre-filled customer object. When present:
  • The checkout page skips the email / customer-info collection step entirely and shows a single “Continue to Pay” button instead.
  • The customer data is passed directly into the payment / onramp flow (no manual input required from the payer).
  • max_uses is automatically forced to 1 — customer-scoped links are always single-use, regardless of any max_uses value supplied in the request.
FieldTypeDescription
emailstring (required)Customer email address
namestringFull name
phonestringPhone number (e.g. +2348012345678)
companystringCompany / organisation name
billing_address_line1stringAddress line 1
billing_address_line2stringAddress line 2
billing_citystringCity
billing_statestringState / province
billing_postal_codestringPostal / ZIP code
billing_countrystringISO 3166-1 alpha-2 country code (e.g. NG)

Examples

curl -X POST https://api.zendfi.tech/api/v1/payment-links \
  -H "Authorization: Bearer zfi_test_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 25.00,
    "description": "Workshop Registration",
    "max_uses": 50,
    "metadata": {"event": "solana-workshop-march"}
  }'

Response

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "link_code": "abc123xyz",
  "description": "Workshop Registration",
  "amount": 25.00,
  "currency": "USD",
  "token": "USDC",
  "hosted_page_url": "https://checkout.zendfi.tech/checkout/abc123xyz",
  "payment_url": "https://checkout.zendfi.tech/checkout/abc123xyz",
  "max_uses": 50,
  "uses_count": 0,
  "expires_at": null,
  "is_active": true,
  "onramp": false,
  "payer_service_charge": false,
  "collect_customer_info": false,
  "customer_data": null,
  "created_at": "2026-03-01T12:00:00Z"
}
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "link_code": "xyz789abc",
  "description": "Order #1042 – Wireless Headphones",
  "amount": 49.00,
  "currency": "USD",
  "token": "USDC",
  "hosted_page_url": "https://checkout.zendfi.tech/checkout/xyz789abc",
  "payment_url": "https://checkout.zendfi.tech/checkout/xyz789abc",
  "max_uses": 1,
  "uses_count": 0,
  "expires_at": null,
  "is_active": true,
  "onramp": true,
  "payer_service_charge": true,
  "collect_customer_info": false,
  "customer_data": {
    "email": "ada@example.com",
    "name": "Ada Lovelace",
    "phone": "+2348012345678",
    "billing_city": "Lagos",
    "billing_country": "NG"
  },
  "created_at": "2026-03-01T12:00:00Z"
}

GET /api/v1/payment-links
Returns all payment links for the authenticated merchant.
const links = await zendfi.listPaymentLinks();

GET /api/v1/payment-links/{link_code}
Retrieves a specific payment link by its code. This endpoint is public — it does not require authentication. This is how the checkout page loads link data.
The unique link code (e.g., abc123xyz).
const link = await zendfi.getPaymentLink('abc123xyz');

POST /api/v1/payment-links/{link_code}/pay
Creates a new payment from a payment link. This is called by the checkout page when a customer opens the link. It is public — no authentication required. When this endpoint is called, it:
  1. Validates the link is active, not expired, and has remaining uses.
  2. Creates a new payment with the link’s parameters.
  3. Returns the payment details including wallet address and QR code.

Use Cases

Invoicing

Create a link and email it to your client. They click, pay, done.

Social Commerce

Share payment links on Twitter, Discord, or Telegram. Accept payments from anywhere.

Event Registration

Set max_uses to your event capacity. Each registration creates a tracked payment.

Donations / Tips

Create an open-ended link for recurring or variable-amount contributions.
When onramp is set to true, the checkout page shows a Pay with Bank option. The customer transfers NGN via bank transfer, which is converted to USDC and settled directly to your wallet.
const link = await zendfi.createPaymentLink({
  amount: 25.00,
  description: 'Product Purchase',
  onramp: true,
  payer_service_charge: true, // transparent fee added on top, billed to payer
});
See the Fiat Onramp guide for details on the full flow.
Pass a customer object when you already know who is paying — for example, when generating a link programmatically from an order management system or a checkout flow on your backend.
const link = await zendfi.createPaymentLink({
  amount: 120.00,
  description: 'Subscription renewal — April 2026',
  onramp: true,
  customer: {
    email: 'customer@example.com',
    name: 'Emeka Obi',
    phone: '+2349023456789',
    billing_country: 'NG',
  },
});
// link.max_uses === 1  (enforced automatically)
Checkout behaviour when customer is present:
  1. The hosted checkout page loads normally.
  2. Instead of showing the email / customer-info form it shows the customer’s name and a “Continue to Pay” button.
  3. Clicking the button proceeds directly to the payment step (crypto wallet or PAJ onramp virtual account screen), with the customer details pre-populated.

Trust and Safety on Hosted Checkout

Hosted checkout includes security controls designed to protect both merchants and customers:
  1. Risk-based payment checks are applied during payment creation, transaction build, and submission.
  2. Sanctions screening is applied during create-payment and transaction-build checkpoints.
  3. Submission-time fraud gates prevent stale-risk bypasses after initial checkout steps.

What customers may see

Depending on risk outcomes, customers may experience:
  • normal payment flow
  • temporary hold / additional review requirement
  • blocked payment attempt
If a payment is blocked or held for review, show neutral language:
“Your payment requires additional security review. Please contact support with your payment ID.”
Avoid showing internal fraud rule details or threshold values in customer-facing UI. For full policy and operations guidance, see Fraud and Compliance.
Because max_uses is locked to 1, customer-scoped links are ideal for invoice payment links, programmatic order links, and any scenario where you need a one-time, identity-bound checkout URL.