Payment Links Endpoints
Create and manage shareable payment/invoice links
/payment-linksRequired
Requires JWT token authentication
Create and manage shareable payment/invoice links
Rate Limit
This endpoint is limited to 100 requests per 1 minute per API key.
Rate limit headers are included in all responses: X-RateLimit-Limit, X-RateLimit-Remaining
Credentials
Your API key is never stored and only used for this request
curl -X POST https://api.ugc.africa/payment-links \ -H "Authorization: Bearer YOUR_API_KEY"
SDK examples (coming soon)
// Official Node SDK - coming soon. Use REST (see Getting Started) or fetch() examples.
// Planned: npm install @UGC/node
Official @UGC/* client libraries are on the roadmap. Integrate with the REST API and webhooks today. SDK pages · Email notify
Success
{
"id": "..."
}curl -X POST https://api.ugc.africa/payment-links \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "iPhone 15 Pro",
"amount": 500000,
"currency": "NGN",
"productType": "PHYSICAL",
"autoReleaseAfterDays": 7,
"customSlug": "iphone-15-pro"
}'All endpoints below are under /payment-links and require a portal session JWT (Authorization: Bearer <jwt>) - the same token your dashboard session uses. See Payment Links guide for the conceptual overview.
Create a payment link
POST /payment-links
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | |
| description | string | No | |
| amount | number | Yes* | Min 1, or min 0 if allowCustomAmount |
| currency | enum | Yes | |
| allowCustomAmount | boolean | No | Customer enters their own amount |
| minAmount | number | No | Min 0.01, when allowCustomAmount is set |
| feeAbsorbedBy | enum | No | MERCHANT (default), CUSTOMER, or SPLIT |
| linkType | enum | No | PAYMENT_LINK (default) or INVOICE |
| lineItems | array | No | { description, quantity, unitPrice }, invoices only |
| taxRate | number | No | 0-1 |
| paymentTerms | string | No | e.g. "Net 30" |
| dueDate | string | No | ISO date, required for invoices |
| productType | enum | No | DIGITAL, PHYSICAL, or SERVICE - enables transaction protection |
| autoReleaseAfterDays | number | No | Min 1, default 7 |
| customSlug | string | No | 3-50 chars, lowercase/numbers/hyphens, auto-lowercased |
| successRedirectUrl | string | No | Where to send the payer after payment |
| maxUses | number | No | Min 1; omit for unlimited |
| expiresAt | string | No | ISO date |
The hosted link is https://ugc.africa/pay/{shortCode} (or the custom slug).
Fund a campaign via payment link
POST /payment-links/campaigns/:campaignId/fund
Same underlying rail, repurposed so a third party without a UGC account can fund one of your campaigns. Settlement emits campaign_funded.
List my payment links
GET /payment-links
Check slug availability
GET /payment-links/check-slug?slug=your-slug
Get a payment link
GET /payment-links/:id
Update a payment link
PATCH /payment-links/:id
Deactivate a payment link
DELETE /payment-links/:id - returns 200, not 204.
Change the slug
PATCH /payment-links/:id/slug - one-time edit.
Download the invoice PDF
GET /payment-links/:id/invoice-pdf - binary PDF response, invoices only.
Common Errors
INVALID_CURRENCYInvalid Currency Code
The currency code provided is not supported.
{
"success": false,
"error": {
"code": "INVALID_CURRENCY",
"message": "Currency code \"XYZ\" is not supported",
"supportedCurrencies": [
"USD",
"EUR",
"GBP",
"GHS",
"NGN"
]
}
}Solution: Use a valid ISO 4217 currency code. See our list of supported currencies.
INSUFFICIENT_BALANCEInsufficient Wallet Balance
The wallet does not have enough balance to complete this transaction.
{
"success": false,
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient balance in USD wallet",
"required": 5000,
"available": 2500
}
}Solution: Add funds to your wallet or use a different payment method.
UNAUTHORIZEDAuthentication Required
The request requires authentication but none was provided.
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or expired authentication token"
}
}Solution: Include a valid API key or JWT token in the Authorization header.
RATE_LIMIT_EXCEEDEDRate Limit Exceeded
Too many requests have been made in a short period.
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Try again in 60 seconds",
"retryAfter": 60
}
}Solution: Wait for the specified retry period before making another request. Consider implementing exponential backoff.
Did this solve your problem?