Create invoices, connect wallet, view payment status and download receipts.
Fundline Documentation
The operating guide for non-custodial USDC invoices on Arc. Fundline helps freelancers, service providers, SaaS tools and agents create invoices, send payment links, verify on-chain payments, issue receipts and trigger Telegram or webhook alerts when a customer pays.
Architecture
How Fundline works
Fundline separates invoice creation, payment execution and payment verification. The app never holds customer funds. PaymentRouter transfers USDC directly from the payer wallet to the merchant wallet.
Stores invoices, verifies Arcscan payments, sends Telegram alerts and dispatches webhooks.
Approves exact USDC spend, calls payInvoice, emits a clear payment event.
| Layer | Responsibility | Custody |
|---|---|---|
| Merchant wallet | Receives USDC directly | User-controlled |
| Payer wallet | Approves and sends USDC | User-controlled |
| PaymentRouter | Routes payment and emits InvoicePaid |
Does not hold funds |
| Server | Stores invoice state and alerts | No token custody |
Quick start
From invoice to paid status
- Start the app server.Open
run-arc-invoice-server.batand visithttp://127.0.0.1:5190. - Connect merchant wallet.The connected wallet becomes the USDC receiving wallet for new invoices.
- Create an invoice.Add client details, due date, note and line items. Fundline calculates total USDC.
- Send the payment link.Share the public
/pay/:invoiceIdlink or QR code with the customer. - Customer pays.The customer can use the wallet payment button or pay manually and verify the transaction.
- Receive alerts and receipt.After verification, the invoice becomes paid, Telegram/webhooks run and PDF receipt becomes available.
Wallet setup
Merchant and payer wallets
The merchant must sign in before creating invoices. This signature proves wallet control and fills the receiving wallet automatically. Payers only need to connect when they want to pay directly through the app. If they pay outside the app, they can paste the payer wallet and transaction hash for verification.
Product
Create invoice
An invoice contains client name, client email, due date, note and line items. The server stores invoices in
data/invoices.json for local demo usage. Production should move this storage to Supabase,
Postgres, or another durable database.
| Field | Purpose |
|---|---|
| Client name | Name shown on invoice, receipt and dashboard. |
| Client email | Reference for sending the payment link or receipt. |
| Due date | Used to flag unpaid invoices as expired. |
| Line items | Services or products with quantity, unit price and total. |
| Payment reference ID | Offchain bytes32 reference created with the invoice. It is written onchain only when PaymentRouter emits InvoicePaid. |
Payment
On-chain payment flow
When PaymentRouter is configured, the public payment page shows a wallet payment button. The payer approves
the exact USDC amount, then calls payInvoice(bytes32,address,uint256).
payInvoice(bytes32 invoiceId, address merchant, uint256 amount)
If PaymentRouter is not configured, the payment page keeps the wallet payment button disabled and still supports manual USDC transfer plus Arcscan verification.
Receipts
PDF receipt and CSV export
Paid invoices can generate a professional PDF receipt. The receipt includes invoice number, payer wallet, receiving wallet, transaction hash, verification source and paid timestamp. Merchants can also export CSV for bookkeeping.
Alerts
Telegram payment alerts
Merchants can add a Telegram chat ID in Settings. After a payment is verified, Fundline sends a message with invoice number, amount, payer wallet, receiving wallet and transaction link.
TELEGRAM_BOT_TOKEN=replace_with_telegram_bot_token
Developers and agents
Agent API
Agent API endpoints let a SaaS backend or AI agent create invoices without using the browser dashboard.
All Agent API requests require a server-side API key. Use Idempotency-Key when an
agent may retry the same create request, so retries return the same invoice instead of creating duplicates.
Authorization: Bearer $FUNDLINE_API_KEY
x-api-key: $FUNDLINE_API_KEY
| Method | Endpoint | Use |
|---|---|---|
| GET | /api/agent/invoices?merchantWallet=:wallet&status=open&limit=100 |
List invoices with optional wallet, status and limit filters. |
| POST | /api/agent/invoices |
Create an invoice and receive paymentLink. |
| GET | /api/agent/invoices/:id |
Fetch one invoice. |
| GET | /api/agent/webhooks |
List webhook subscriptions. |
| POST | /api/agent/webhooks |
Create or replace a webhook subscription. |
| PATCH | /api/agent/webhooks/:id |
Update webhook URL, secret or enabled state. |
| GET | /api/agent/webhook-logs |
Review webhook delivery attempts. |
curl -X POST http://127.0.0.1:5190/api/agent/invoices \
-H "Authorization: Bearer $FUNDLINE_API_KEY" \
-H "Idempotency-Key: client-ltd-2026-06-retainer" \
-H "Content-Type: application/json" \
-d '{
"merchantWallet": "0x8124ca3f0ca935e6beb69f2857e33d32fa3b54ea",
"merchantName": "Fundline Studio",
"clientName": "Client Ltd",
"clientEmail": "billing@client.com",
"dueDate": "2026-06-30",
"items": [
{ "description": "Consulting package", "quantity": 1, "unitPrice": 250 }
]
}'
Webhooks
Payment events for external systems
Webhooks notify your backend when an invoice becomes paid. A webhook can be signed with
X-Fundline-Signature using HMAC SHA-256.
curl -X POST http://127.0.0.1:5190/api/agent/webhooks \
-H "Authorization: Bearer $FUNDLINE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"merchantWallet": "0x8124ca3f0ca935e6beb69f2857e33d32fa3b54ea",
"url": "https://example.com/webhooks/fundline",
"event": "invoice.paid",
"secret": "optional_shared_secret"
}'
{
"event": "invoice.paid",
"sentAt": "2026-06-11T00:00:00.000Z",
"invoice": {
"id": "37f1cdd4727c0d85d32b",
"number": "INV-2026-0001",
"status": "paid",
"total": 250,
"merchantWallet": "0x...",
"payerWallet": "0x...",
"txHash": "0x...",
"paymentLink": "http://127.0.0.1:5190/pay/37f1cdd4727c0d85d32b"
}
}
Delivery audit
Webhook logs
Each webhook delivery attempt is stored on the server with delivery ID, invoice ID, target URL, success state, HTTP status, error preview and duration. Secrets are never returned in log responses.
curl "http://127.0.0.1:5190/api/agent/webhook-logs?merchantWallet=0x8124ca3f0ca935e6beb69f2857e33d32fa3b54ea&limit=20" \
-H "Authorization: Bearer $FUNDLINE_API_KEY"
| Filter | Use |
|---|---|
merchantWallet |
Show logs for one merchant receiving wallet. |
webhookId |
Debug one webhook endpoint. |
invoiceId |
Check delivery attempts for one invoice. |
ok=true|false |
Separate successful and failed delivery attempts. |
Reference
Network
| Network | Arc Testnet |
|---|---|
| Chain ID | 5042002 |
| RPC | https://rpc.testnet.arc.network |
| Explorer | testnet.arcscan.app |
| USDC | 0x3600000000000000000000000000000000000000 |
Contracts
PaymentRouter
PaymentRouter was deployed to Arc Testnet to enable direct USDC invoice payments from payer wallet to merchant wallet.
| Contract | 0x7f3bCf33711F981e2d67870D5Cdb5503f01e1a24 |
|---|---|
| Deploy tx | 0x56d6f6d33bffb02c862239bdcce8f7c2c5129786396bda7efdbf248e89ddb92d |
| Block | 46561912 |
| Source | contracts/PaymentRouter.sol |
Configuration
Server environment
All secrets stay on the server. Do not expose private keys, Telegram bot token or API key in browser code.
TELEGRAM_BOT_TOKEN=replace_with_telegram_bot_token
FUNDLINE_API_KEY=replace_with_a_long_random_agent_api_key
ARC_DEPLOYER_PRIVATE_KEY=replace_with_testnet_deployer_private_key
ARCSCAN_API_BASE=https://testnet.arcscan.app/api/v2
ARCSCAN_EXPLORER_BASE=https://testnet.arcscan.app
ARC_CHAIN_ID=5042002
ARC_RPC_URL=https://rpc.testnet.arc.network
ARC_NETWORK_NAME=Arc Testnet
ARC_USDC_TOKEN_ADDRESS=0x3600000000000000000000000000000000000000
ARC_NATIVE_USDC_DECIMALS=18
ARC_PAYMENT_ROUTER_ADDRESS=0x7f3bCf33711F981e2d67870D5Cdb5503f01e1a24
Security
Security baseline
- PaymentRouter is non-custodial and does not hold USDC.
- The payer approves only the invoice amount required by the payment page.
- Paid status is set only after Arcscan returns a matching payment.
- Telegram bot token, API key and deployer private key stay in server-side environment files.
- Webhook signatures should be verified by production receivers before trusting payloads.
FAQ
Common questions
Does Fundline hold customer money?
No. PaymentRouter transfers USDC from payer wallet directly to merchant wallet.
Can a payer pay without connecting wallet?
Yes. They can send USDC manually and then provide payer wallet plus optional transaction hash for verification.
Is local JSON storage production ready?
No. It is useful for demo and local development. Production should use a database.
What should be built next?
Direct PaymentRouter event indexing, hosted database, invoice email delivery, and a hosted admin UI for webhook delivery logs.