List Payment Links
The List Payment Links endpoint retrieves all payment links associated with your application. It supports pagination and automatically filters results to show only payment links that belong to your authenticated application, ensuring data isolation and security.
Endpoint DetailsCopied!
-
Method:
GET
-
URL:
/api/v0/payment-links
-
Content-Type:
application/json
-
Authentication: Required (
x-client-key
andx-client-secret
) -
Scope Required:
payment_link:list
Request HeadersCopied!
Header |
Type |
Required |
Description |
---|---|---|---|
|
string |
Yes |
Your API client key |
|
string |
Yes |
Your API client secret |
Query ParametersCopied!
Parameter |
Type |
Required |
Default |
Description |
---|---|---|---|---|
|
integer |
No |
0 |
Number of records to skip (must be non-negative) |
|
integer |
No |
10 |
Number of records to return (must be positive, max recommended: 100) |
Pagination Guidelines
-
skip: Use for offset-based pagination (0, 10, 20, etc.)
-
take: Controls page size, keep reasonable (≤100) for performance
-
Maximum take: While not enforced, values >100 may impact performance
ResponseCopied!
Success Response (200 OK)
Returns an array of payment link objects:
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Premium Subscription",
"description": "Monthly access to all premium features",
"url": "premium-subscription",
"linkType": "PRODUCT",
"status": "ACTIVE",
"amount": 29.99,
"currency": "usdc",
"recurringType": "MONTHLY",
"walletId": "wallet_550e8400-e29b-41d4-a716-446655440000",
"appId": "app_550e8400-e29b-41d4-a716-446655440000",
"allowQuantityAdjustment": true,
"collectTax": false,
"collectAddress": true,
"requirePhoneNumber": true,
"limitPayments": false,
"maxPayments": null,
"allowBusinessTaxId": false,
"allowMobilePayment": true,
"confirmationPage": "SHOW",
"createInvoicePdf": true,
"allowCryptoPayment": true,
"isForAllProduct": false,
"customFields": null,
"expiration_date": null,
"customerId": null,
"taxId": null,
"createdAt": "2024-01-15T10:30:00Z",
"coverImage": "https://example.com/images/premium.jpg",
"paymentForId": null
},
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"title": "Startup Bundle",
"description": "Everything you need to get started",
"url": "startup-bundle",
"linkType": "PRODUCT",
"status": "ACTIVE",
"amount": null,
"currency": "usdc",
"recurringType": "ONE_TIME",
"walletId": "wallet_550e8400-e29b-41d4-a716-446655440000",
"appId": "app_550e8400-e29b-41d4-a716-446655440000",
"allowQuantityAdjustment": true,
"collectTax": true,
"collectAddress": true,
"requirePhoneNumber": false,
"limitPayments": true,
"maxPayments": 100,
"allowBusinessTaxId": true,
"allowMobilePayment": false,
"confirmationPage": "SHOW",
"createInvoicePdf": false,
"allowCryptoPayment": true,
"isForAllProduct": false,
"customFields": {
"company_size": "required",
"use_case": "optional"
},
"expiration_date": "2024-12-31T23:59:59Z",
"customerId": null,
"taxId": "tax_550e8400-e29b-41d4-a716-446655440000",
"createdAt": "2024-01-10T08:15:00Z",
"coverImage": null,
"paymentForId": "bundle_2024"
}
]
Empty Response
When no payment links exist:
[]
Error Responses
400 Bad Request - Invalid Pagination
{
"statusCode": 400,
"message": "Skip parameter must be a non-negative number",
"error": "Bad Request"
}
{
"statusCode": 400,
"message": "Take parameter must be a positive number",
"error": "Bad Request"
}
401 Unauthorized - Invalid Authentication
{
"statusCode": 401,
"message": "Application not authenticated",
"error": "Unauthorized"
}
403 Forbidden - Insufficient Scope
{
"statusCode": 403,
"message": "Insufficient scope for this operation",
"error": "Forbidden"
}
429 Too Many Requests
{
"statusCode": 429,
"message": "Rate limit exceeded",
"error": "Too Many Requests"
}
Example RequestsCopied!
Basic List Request
curl -X GET "https://api.devdraft.com/api/v0/payment-links" \
-H "x-client-key: your_client_key" \
-H "x-client-secret: your_client_secret"
Paginated Request
curl -X GET "https://api.devdraft.com/api/v0/payment-links?skip=20&take=10" \
-H "x-client-key: your_client_key" \
-H "x-client-secret: your_client_secret"
First Page (Initial Load)
curl -X GET "https://api.devdraft.com/api/v0/payment-links?skip=0&take=25" \
-H "x-client-key: your_client_key" \
-H "x-client-secret: your_client_secret"
Response FieldsCopied!
Core Information
Field |
Type |
Description |
---|---|---|
|
string |
Unique payment link identifier |
|
string |
Display title of the payment link |
|
string |
Detailed description (nullable) |
|
string |
URL slug for the payment link |
|
datetime |
Creation timestamp |
Payment Configuration
Field |
Type |
Description |
---|---|---|
|
enum |
Type of payment link ( |
|
enum |
Current status ( |
|
number |
Fixed amount (nullable for product bundles) |
|
enum |
Payment currency ( |
|
enum |
Payment frequency |
|
datetime |
Link expiration (nullable) |
Associated Resources
Field |
Type |
Description |
---|---|---|
|
string |
Associated wallet identifier |
|
string |
Your application identifier |
|
string |
Specific customer ID (nullable) |
|
string |
Tax configuration ID (nullable) |
|
string |
External reference ID (nullable) |
Customer Experience Settings
Field |
Type |
Description |
---|---|---|
|
boolean |
Can customers adjust quantities |
|
boolean |
Tax collection enabled |
|
boolean |
Address collection required |
|
boolean |
Phone number required |
|
boolean |
Business tax ID collection |
|
boolean |
Mobile payment options enabled |
|
boolean |
Cryptocurrency payments enabled |
Advanced Settings
Field |
Type |
Description |
---|---|---|
|
boolean |
Payment count limited |
|
number |
Maximum payment count (nullable) |
|
boolean |
Includes all products from catalog |
|
enum |
Post-payment page behavior |
|
boolean |
Generate PDF receipts |
|
object |
Custom form fields (nullable) |
|
string |
Cover image URL (nullable) |
Integration PatternsCopied!
Basic Pagination Implementation
async function getAllPaymentLinks() {
const allLinks = [];
let skip = 0;
const take = 25;
let hasMore = true;
while (hasMore) {
const response = await fetch(
`/api/v0/payment-links?skip=${skip}&take=${take}`,
{
headers: {
'x-client-key': 'your_client_key',
'x-client-secret': 'your_client_secret'
}
}
);
const links = await response.json();
allLinks.push(...links);
// If we got fewer results than requested, we've reached the end
hasMore = links.length === take;
skip += take;
}
return allLinks;
}
React Component Example
import { useState, useEffect } from 'react';
function PaymentLinksList() {
const [links, setLinks] = useState([]);
const [loading, setLoading] = useState(true);
const [page, setPage] = useState(0);
const pageSize = 10;
useEffect(() => {
fetchPaymentLinks();
}, [page]);
const fetchPaymentLinks = async () => {
setLoading(true);
try {
const response = await fetch(
`/api/v0/payment-links?skip=${page * pageSize}&take=${pageSize}`,
{
headers: {
'x-client-key': process.env.REACT_APP_CLIENT_KEY,
'x-client-secret': process.env.REACT_APP_CLIENT_SECRET
}
}
);
const data = await response.json();
setLinks(data);
} catch (error) {
console.error('Failed to fetch payment links:', error);
} finally {
setLoading(false);
}
};
return (
<div>
{loading ? (
<div>Loading...</div>
) : (
<div>
{links.map(link => (
<div key={link.id} className="payment-link-card">
<h3>{link.title}</h3>
<p>{link.description}</p>
<span className={`status ${link.status.toLowerCase()}`}>
{link.status}
</span>
<div className="link-type">{link.linkType}</div>
{link.amount && (
<div className="amount">
{link.amount} {link.currency.toUpperCase()}
</div>
)}
</div>
))}
<div className="pagination">
<button
onClick={() => setPage(p => Math.max(0, p - 1))}
disabled={page === 0}
>
Previous
</button>
<span>Page {page + 1}</span>
<button
onClick={() => setPage(p => p + 1)}
disabled={links.length < pageSize}
>
Next
</button>
</div>
</div>
)}
</div>
);
}
Filtering and Search
// Client-side filtering example
function filterPaymentLinks(links, filters) {
return links.filter(link => {
// Filter by status
if (filters.status && link.status !== filters.status) {
return false;
}
// Filter by type
if (filters.linkType && link.linkType !== filters.linkType) {
return false;
}
// Search by title
if (filters.search &&
!link.title.toLowerCase().includes(filters.search.toLowerCase())) {
return false;
}
// Filter by currency
if (filters.currency && link.currency !== filters.currency) {
return false;
}
return true;
});
}
// Usage
const filteredLinks = filterPaymentLinks(allLinks, {
status: 'ACTIVE',
linkType: 'PRODUCT',
search: 'subscription',
currency: 'usdc'
});
Performance ConsiderationsCopied!
Optimal Page Sizes
Use Case |
Recommended |
Reasoning |
---|---|---|
Dashboard lists |
10-25 |
Quick loading, good UX |
Data tables |
25-50 |
Balance between performance and content |
Bulk operations |
50-100 |
Efficient for processing |
Mobile apps |
10-20 |
Limited screen space |
Caching Strategy
class PaymentLinksCache {
constructor() {
this.cache = new Map();
this.cacheTimeout = 5 * 60 * 1000; // 5 minutes
}
getCacheKey(skip, take) {
return `links_${skip}_${take}`;
}
async getPaymentLinks(skip = 0, take = 10) {
const cacheKey = this.getCacheKey(skip, take);
const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
return cached.data;
}
const response = await fetch(
`/api/v0/payment-links?skip=${skip}&take=${take}`,
{
headers: {
'x-client-key': 'your_client_key',
'x-client-secret': 'your_client_secret'
}
}
);
const data = await response.json();
this.cache.set(cacheKey, {
data,
timestamp: Date.now()
});
return data;
}
invalidateCache() {
this.cache.clear();
}
}
Error Handling Best PracticesCopied!
async function fetchPaymentLinksWithRetry(skip = 0, take = 10, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(
`/api/v0/payment-links?skip=${skip}&take=${take}`,
{
headers: {
'x-client-key': 'your_client_key',
'x-client-secret': 'your_client_secret'
}
}
);
if (response.status === 429) {
// Rate limited - wait and retry
const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
if (attempt === maxRetries) {
throw new Error(`Failed to fetch payment links after ${maxRetries} attempts: ${error.message}`);
}
// Wait before retry
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
}
}
Rate LimitingCopied!
-
Limit: 100 requests per minute per API key
-
Headers: Monitor
X-RateLimit-*
headers -
Best Practice: Implement caching and pagination to minimize requests
Security FeaturesCopied!
-
App Isolation: Results automatically filtered by your application
-
No Cross-App Data: Cannot access other applications' payment links
-
Authentication Required: All requests must include valid API credentials
-
Scope Validation: Requires
payment_link:list
scope
Common Use CasesCopied!
Dashboard Integration
Display all payment links in your admin dashboard with pagination and search functionality.
Analytics & Reporting
Fetch all payment links to generate performance reports and usage analytics.
Bulk Operations
Retrieve payment links for bulk status updates, expiration management, or cleanup operations.
Mobile Applications
Implement efficient pagination for mobile apps with limited screen space.
Third-party Integrations
Sync payment link data with external CRM, accounting, or marketing systems.