Skip to Content
Finance

Finance

Read financial summaries and the transaction ledger, and create shareable payment links for a sale, a debt, or a one-off wallet top-up. Everything here only ever collects money into your own wallet - creating a payment link doesn’t move money out, so payment_links:write isn’t a finance-write scope requiring an IP allowlist. For moving money out, see Wallet & payouts.

Summaries and transactions

All endpoints share the prefix /v1/finance and authenticate with an API key.

EndpointScope
GET /v1/finance/summaryfinance:summary:read
GET /v1/finance/transactionsfinance:transactions:read
GET /v1/finance/transactions/:idfinance:transactions:read
POST /v1/finance/transactions/:id/requeryfinance:transactions:read
POST /v1/finance/transactions/:id/receiptfinance:transactions:read

finance:read grants both child read scopes.

Get a summary

GET /v1/finance/summary

Query parameters

ParameterTypeDescription
from, toISO dateReturn a period summary for this range
dateISO dateReturn a daily summary for this date (used only when from/to are absent; defaults to today)
store_iduuidScope to a single store
{ "message": "Financial summary retrieved", "data": { "date": "2026-01-15", "isToday": true, "currency": "NGN", "walletBalance": 250000, "salesTotal": 180000, "pendingOrdersCount": 3, "pendingOrdersTotal": 45000, "expensesTotal": 20000, "pendingDebtTotal": 12000, "creditsTotal": 175000, "pendingTransactionsCount": 2, "velocityData": [ { "intervalStart": "2026-01-15T10:00:00.000+01:00", "value": 30000 }, { "intervalStart": "2026-01-15T11:00:00.000+01:00", "value": 45000 } ] } }

Money fields are numeric values in the currency identified by currency. Format them in your application using the user’s locale and the returned ISO 4217 currency code.

Each velocityData entry is a sales-total bucket. intervalStart is an ISO 8601 timestamp with an offset. Daily summaries use hourly buckets; period summaries use daily buckets.

Passing from and to returns the same shape plus startDate, endDate, periodLabel, and totalDays.

List transactions

GET /v1/finance/transactions

Covers every money movement recorded against the business - sales, expenses, wallet deposits/withdrawals, refunds, and more.

Query parameters

ParameterTypeDescription
pagenumberPage number (default 1)
limitnumberItems per page (default 20, max 50)
store_iduuidFilter by store
searchstringSearch reference, customer name
statusenum listComma-separated: cleared, pending, processing, failed, cancelled
typeenum listComma-separated direction: credit, debit
categoryenum listComma-separated: sale, expense, wallet, other
customer_iduuidFilter by the Cloove customer ID returned by payment links and webhooks
customer_emailemailResolve and filter by a business customer’s email
customer_phonestringResolve and filter by a business customer’s normalized phone identity

Use customer_id by itself, or use customer_email and customer_phone. Do not combine customer_id with the email or phone filters. Customer resolution is always scoped to the authenticated business. An unknown email or phone returns an empty transaction list.

{ "message": "Transactions retrieved", "data": [ { "id": "tx1a2b3c-...", "reference": "CLV-TX-0001", "type": "credit", "amount": 5000, "customer": "Ada Lovelace", "status": "cleared", "date": "2026-01-15", "dateLabel": "15 Jan, 10:00 AM", "fullDate": "2026-01-15T10:00:00.000Z", "method": "Card", "storeId": "st1a2b3c-...", "customerId": "cus1a2b3c-...", "customerEmail": "ada@example.com", "customerPhone": "2348012345678", "paymentLinkId": "pl1a2b3c-...", "paymentLinkReference": "CLV-PL-0001" } ], "meta": { "total": 1, "page": 1, "perPage": 20, "totalPages": 1, "hasMore": false } }

Get a transaction

GET /v1/finance/transactions/:id

Returns 404 not_found if the ID doesn’t belong to your business.

Requery a transaction

POST /v1/finance/transactions/:id/requery

Re-checks the transaction’s status with the payment provider and updates it if it has changed. Useful when a webhook was missed or delayed.

Generate a receipt

POST /v1/finance/transactions/:id/receipt
{ "message": "Receipt generated", "data": { "url": "https://.../receipts/tx1a2b3c.pdf" } }

Shareable checkout links for an existing sale, an existing debt, or a one-off wallet top-up. All endpoints share the prefix /v1/payment-links.

EndpointScope
GET /v1/payment-linkspayment_links:read
GET /v1/payment-links/:idpayment_links:read
POST /v1/payment-linkspayment_links:write
POST /v1/payment-links/wallet/dynamicpayment_links:write
DELETE /v1/payment-links/:idpayment_links:write

This is the same feature as the dashboard’s Payment links, scoped for API keys. Once created, a link is shared and paid the same way regardless of how it was created. See Checkout for the public checkout flow.

A business can select multiple checkout virtual account providers in Sales settings. The hosted checkout shows the selected providers, and Cloove randomly chooses one for each new virtual account. Leaving the selection empty uses the workspace default, so existing integrations continue to work without additional configuration.

GET /v1/payment-links

Query parameters

ParameterTypeDescription
pagenumberPage number (default 1)
limitnumberItems per page (default 20)
statusstringACTIVE, PAID, EXPIRED, CANCELLED
target_typestringSALE, DEBT, WALLET
searchstringSearch reference, title, customer name/email
customer_iduuidFilter by the Cloove customer ID returned by payment links and webhooks
customer_emailemailResolve and filter by a business customer’s email
customer_phonestringResolve and filter by a business customer’s normalized phone identity

Use customer_id by itself, or use customer_email and customer_phone. Do not combine customer_id with the email or phone filters. Customer resolution is scoped to the authenticated business. An unknown email or phone returns an empty payment-link list.

{ "message": "Payment links retrieved", "data": [ { "id": "pl1a2b3c-...", "reference": "CLV-PL-0001", "targetType": "sale", "targetId": "s1a2b3c4-...", "title": null, "amount": 15000, "currency": "NGN", "customerName": "Ada Lovelace", "customerEmail": "ada@example.com", "customerPhone": "+2348012345678", "customerId": "cus1a2b3c-...", "description": "Invoice INV-2026-001", "redirectUrl": "https://merchant.example/orders/INV-2026-001", "status": "active", "isReusable": false, "isStatic": false, "expiresAt": null, "createdAt": "2026-01-15T10:00:00.000Z" } ], "meta": { "total": 1, "page": 1, "perPage": 20, "totalPages": 1, "hasMore": false } }
GET /v1/payment-links/:id
POST /v1/payment-links

Creates (or returns the existing active link for) a payment collection URL against an existing SALE or DEBT. The amount is derived from the target’s outstanding balance - you don’t set it directly.

Body

FieldTypeRequiredDescription
target_typeenumYessale or debt
target_iduuidYesThe sale or debt ID
expires_atdatetimeNoWhen the link stops accepting payment
descriptionstringNoShown on the checkout page
record_as_salebooleanNoFor DEBT links: also record the payment as a sale
redirect_urlURLNoHTTP or HTTPS destination after a terminal checkout outcome
customerobjectNoCustomer information used to map the link to a business customer
{ "target_type": "sale", "target_id": "60dd38ab-85f1-4e7c-9f63-7c6072199918", "redirect_url": "https://merchant.example/orders/INV-2026-001", "customer": { "name": "Ada Lovelace", "email": "ada@example.com", "phone_number": "+2348012345678" } }

Response 201 Created. Send an Idempotency-Key header to avoid duplicates.

POST /v1/payment-links/wallet/dynamic

A one-off, amount-based link that funds your own wallet when paid. Use it for an invoice or another payment that is not tied to an existing sale.

Body

FieldTypeRequiredDescription
titlestringYesShown on the checkout page
amountnumberYesAmount to collect
descriptionstringNoShown on the checkout page
expires_atdatetimeNoWhen the link stops accepting payment
redirect_urlURLNoHTTP or HTTPS destination after a terminal checkout outcome
customerobjectNoCustomer information used to map the link to a business customer
{ "title": "Consulting deposit", "amount": 50000, "redirect_url": "https://merchant.example/deposits/result", "customer": { "name": "Ada Lovelace", "email": "ada@example.com" } }

Response 201 Created. Send an Idempotency-Key header to avoid duplicates.

Customer identity and matching

The optional customer object supports:

FieldTypeRequiredDescription
namestringNoCustomer display name
emailemailConditionalCase-insensitive customer identity within the business
phone_numberstringConditionalNormalized customer identity within the business

Provide at least one of email or phone_number when sending customer. Cloove looks for an active customer belonging to the authenticated business. If no customer matches, Cloove creates one and stores its customerId on the payment link. If email and phone number match different customers, the request fails instead of linking the payment to the wrong customer.

For sale and debt links, omitting customer keeps the customer already attached to the target. Providing customer explicitly sets the payment link’s customer mapping.

Customer matching never crosses business boundaries. The customer fields returned on a payment link are snapshots used to prefill checkout, while customerId is the durable customer mapping.

DELETE /v1/payment-links/:id

Marks the link CANCELLED. It stops accepting payment but is not deleted.

Redirect after checkout

When redirect_url is present, the hosted checkout redirects the payer after payment, cancellation, or link expiry. Cloove preserves existing query parameters and adds:

ParameterValues
payment_statuspaid, cancelled, or expired
payment_referenceThe Cloove payment-link reference

For example:

https://merchant.example/orders/INV-2026-001?payment_status=paid&payment_reference=CLV-PL-0001

Treat redirect parameters as user-facing navigation context, not proof of payment. Verify the transaction using payment.received webhooks or the transaction APIs before fulfilling an order.

Last updated on