{"repo":"egokiemute/clink","private":false,"description":"Clink backend and sdk","default_branch":"main","stars":0,"forks":0,"pushed_at":"2026-09-03T06:41:53Z","languages":{"TypeScript":117567,"JavaScript":2446},"files":95,"tree":[".DS_Store",".dockerignore",".env.example",".github/workflows/keep-alive.yml",".gitignore","DOCUMENTATION.md","README.md","api/webhooks/clink.js","clink-sdk-spec.md","clink.sqlite","dist/index.d.ts","dist/index.d.ts.map","dist/index.js","dist/index.js.map","dist/paychant/client.d.ts","dist/paychant/client.d.ts.map","dist/paychant/client.js","dist/paychant/client.js.map","dist/payments/service.d.ts","dist/payments/service.d.ts.map","dist/payments/service.js","dist/payments/service.js.map","dist/stellar/client.d.ts","dist/stellar/client.d.ts.map","dist/stellar/client.js","dist/stellar/client.js.map","dist/storage/sqlite.d.ts","dist/storage/sqlite.d.ts.map","dist/storage/sqlite.js","dist/storage/sqlite.js.map","dist/types/index.d.ts","dist/types/index.d.ts.map","dist/types/index.js","dist/types/index.js.map","dist/utils/crypto.d.ts","dist/utils/crypto.d.ts.map","dist/utils/crypto.js","dist/utils/crypto.js.map","dist/utils/errors.d.ts","dist/utils/errors.d.ts.map","dist/utils/errors.js","dist/utils/errors.js.map","dist/utils/validation.d.ts","dist/utils/validation.d.ts.map","dist/utils/validation.js","dist/utils/validation.js.map","dist/webhooks/deliver.d.ts","dist/webhooks/deliver.d.ts.map","dist/webhooks/deliver.js","dist/webhooks/deliver.js.map","dist/webhooks/verify.d.ts","dist/webhooks/verify.d.ts.map","dist/webhooks/verify.js","dist/webhooks/verify.js.map","examples/manual-demo.ts","examples/verify-payment.ts","jest.config.cjs","package-lock.json","package.json","plans/hosted-payment-page.md","plans/merchant-wallets-and-withdrawals.md","plans/multi-chain-support.md","project.toml","render.yaml","scripts/backfill-wallets.ts","scripts/setup-testnet-funder.ts","src/developers/service.ts","src/index.ts","src/mailer/index.ts","src/merchants/walletService.ts","src/merchants/withdrawalService.ts","src/payments/service.ts","src/server.ts","src/settlement/mock.ts","src/settlement/payoutProvider.ts","src/settlement/paystackSettlement.ts","src/stellar/client.ts","src/storage/admins.ts","src/storage/bankAccounts.ts","src/storage/developers.ts","src/storage/payments.ts","src/storage/pg.ts","src/storage/withdrawals.ts","src/types/index.ts","src/utils/crypto.ts","src/utils/encryption.ts","src/utils/errors.ts","src/utils/validation.ts","src/webhooks/deliver.ts","src/webhooks/verify.ts","tests/clink.test.ts","tests/payments.test.ts","tests/webhooks.test.ts","tsconfig.json","vercel.json"],"sizes":{".DS_Store":6148,".dockerignore":69,".env.example":631,".github/workflows/keep-alive.yml":439,".gitignore":108,"DOCUMENTATION.md":13371,"README.md":5186,"api/webhooks/clink.js":2243,"clink-sdk-spec.md":13106,"clink.sqlite":28672,"dist/index.d.ts":1001,"dist/index.d.ts.map":950,"dist/index.js":5351,"dist/index.js.map":2530,"dist/paychant/client.d.ts":409,"dist/paychant/client.d.ts.map":464,"dist/paychant/client.js":2310,"dist/paychant/client.js.map":1780,"dist/payments/service.d.ts":1593,"dist/payments/service.d.ts.map":1481,"dist/payments/service.js":5134,"dist/payments/service.js.map":4044,"dist/stellar/client.d.ts":2104,"dist/stellar/client.d.ts.map":2200,"dist/stellar/client.js":10563,"dist/stellar/client.js.map":8750,"dist/storage/sqlite.d.ts":669,"dist/storage/sqlite.d.ts.map":773,"dist/storage/sqlite.js":5070,"dist/storage/sqlite.js.map":3619,"dist/types/index.d.ts":3006,"dist/types/index.d.ts.map":3145,"dist/types/index.js":110,"dist/types/index.js.map":111,"dist/utils/crypto.d.ts":402,"dist/utils/crypto.d.ts.map":421,"dist/utils/crypto.js":1265,"dist/utils/crypto.js.map":1097,"dist/utils/errors.d.ts":627,"dist/utils/errors.d.ts.map":522,"dist/utils/errors.js":395,"dist/utils/errors.js.map":337,"dist/utils/validation.d.ts":388,"dist/utils/validation.d.ts.map":399,"dist/utils/validation.js":1937,"dist/utils/validation.js.map":1449,"dist/webhooks/deliver.d.ts":661,"dist/webhooks/deliver.d.ts.map":686,"dist/webhooks/deliver.js":2164,"dist/webhooks/deliver.js.map":1623,"dist/webhooks/verify.d.ts":313,"dist/webhooks/verify.d.ts.map":325,"dist/webhooks/verify.js":1164,"dist/webhooks/verify.js.map":927,"examples/manual-demo.ts":1294,"examples/verify-payment.ts":848,"jest.config.cjs":203,"package-lock.json":177100,"package.json":1213,"plans/hosted-payment-page.md":9243,"plans/merchant-wallets-and-withdrawals.md":14580,"plans/multi-chain-support.md":16214,"project.toml":178,"render.yaml":2017,"scripts/backfill-wallets.ts":4121,"scripts/setup-testnet-funder.ts":2111,"src/developers/service.ts":1875,"src/index.ts":4229,"src/mailer/index.ts":7032,"src/merchants/walletService.ts":1584,"src/merchants/withdrawalService.ts":5296,"src/payments/service.ts":5390,"src/server.ts":25454,"src/settlement/mock.ts":586,"src/settlement/payoutProvider.ts":6077,"src/settlement/paystackSettlement.ts":1647,"src/stellar/client.ts":10672,"src/storage/admins.ts":930,"src/storage/bankAccounts.ts":2476,"src/storage/developers.ts":5911,"src/storage/payments.ts":4477,"src/storage/pg.ts":4477,"src/storage/withdrawals.ts":4193,"src/types/index.ts":2849,"src/utils/crypto.ts":1031,"src/utils/encryption.ts":1353,"src/utils/errors.ts":609,"src/utils/validation.ts":1690,"src/webhooks/deliver.ts":2129,"src/webhooks/verify.ts":1064,"tests/clink.test.ts":1318,"tests/payments.test.ts":6030,"tests/webhooks.test.ts":956,"tsconfig.json":500,"vercel.json":242},"readme":"# clink-sdk\n\nAccept USDC payments on Stellar and receive local currency payouts (NGN, GHS, KES, UGX).\n\n## Requirements\n\n- Node.js >= 24\n\n## Installation\n\n```bash\nnpm install clink-sdk\n```\n\n## Quick start\n\n```ts\nimport Clink from 'clink-sdk';\n\nconst clink = new Clink({\n  secretKey: process.env.CLINK_SECRET_KEY,      // must start with clink_sk_\n  environment: 'testnet',                        // or 'mainnet'\n  receivingAddress: process.env.STELLAR_RECEIVING_ADDRESS,\n  webhookSecret: process.env.CLINK_WEBHOOK_SECRET,\n});\n```\n\n## Configuration\n\n| Option | Required | Description |\n|---|---|---|\n| `secretKey` | Yes | Your Clink secret key — must start with `clink_sk_` |\n| `environment` | Yes | `'testnet'` or `'mainnet'` |\n| `receivingAddress` | Yes* | Stellar public key to receive USDC payments |\n| `stellarSecretKey` | Yes* | Stellar secret key (alternative to `receivingAddress`) |\n| `webhookSecret` | No | Secret used to sign webhook payloads (falls back to `secretKey`) |\n| `databasePath` | No | Path to SQLite file (default: `./clink.sqlite`) |\n| `paymentExpiryMinutes` | No | Minutes until a pending payment expires (default: `30`) |\n| `stellarHorizonUrl` | No | Custom Horizon URL (defaults to public testnet/mainnet) |\n\n*Provide either `receivingAddress` or `stellarSecretKey`.\n\n## Payments\n\n### Create a payment\n\n```ts\nconst payment = await clink.payments.create({\n  amount: 10,                        // USDC amount\n  currency: 'USDC',\n  localCurrency: 'NGN',              // 'NGN' | 'GHS' | 'KES' | 'UGX'\n  callbackUrl: 'https://yourapp.com/webhooks/clink',\n  description: 'Order #1234',        // optional\n  customerEmail: 'user@example.com', // optional\n  metadata: { orderId: '1234' },     // optional, returned in webhooks\n});\n```\n\nResponse:\n\n```json\n{\n  \"id\": \"pay_abc123\",\n  \"stellarAddress\": \"G...\",\n  \"memo\": \"CLINK-abc123\",\n  \"amount\": 10,\n  \"currency\": \"USDC\",\n  \"localCurrency\": \"NGN\",\n  \"status\": \"pending\",\n  \"expiresAt\": \"2025-01-01T00:30:00.000Z\",\n  \"createdAt\": \"2025-01-01T00:00:00.000Z\"\n}\n```\n\nShow the customer `stellarAddress` and `memo` — they must include the memo when sending USDC or the payment cannot be matched.\n\n### Check payment status\n\n```ts\nconst payment = await clink.payments.verify('pay_abc123');\n// Checks Stellar for the incoming transaction and triggers settlement\n```\n\n### List payments\n\n```ts\nconst payments = await clink.payments.list();\n\n// With filters\nconst pending = await clink.payments.list({ status: 'pending', limit: 20 });\n```\n\n## Payment lifecycle\n\n```\npending → confirmed → settled\n       ↘ expired\n       ↘ failed\n```\n\n| Status | Meaning |\n|---|---|\n| `pending` | Awaiting USDC on Stellar |\n| `confirmed` | USDC received on Stellar, settlement in progress |\n| `settled` | Converted to local currency and paid out |\n| `expired` | Payment not received before `paymentExpiryMinutes` elapsed |\n| `failed` | Settlement failed |\n\n## Webhooks\n\nClink POSTs a signed payload to `callbackUrl` on each status change.\n\n### Events\n\n| Event | Fired when |\n|---|---|\n| `payment.confirmed` | USDC received on Stellar |\n| `payment.settled` | Local currency payout complete |\n| `payment.failed` | Settlement failed |\n| `payment.expired` | Payment expired before USDC was received |\n\n### Payload\n\n```json\n{\n  \"event\": \"payment.settled\",\n  \"data\": { ...payment },\n  \"signature\": \"sha256=...\"\n}\n```\n\nThe signature is also sent as the `x-clink-signature` request header.\n\n### Verifying signatures\n\nAlways verify the signature before processing a webhook:\n\n```ts\nimport express from 'express';\nimport Clink from 'clink-sdk';\n\nconst clink = new Clink({ ... });\nconst app = express();\n\napp.post('/webhooks/clink', express.json(), (req, res) => {\n  const valid = clink.webhooks.verify({\n    payload: req.body,\n    signature: req.headers['x-clink-signature'] as string,\n    secret: process.env.CLINK_WEBHOOK_SECRET,\n  });\n\n  if (!valid) {\n    return res.status(401).json({ error: 'Invalid signature' });\n  }\n\n  const { event, data } = req.body;\n\n  if (event ","price_usd":"80.00","clone_checkout":"https://api.checkout402.com/c/chk_npD-wqTKN7B3ydxa","rehearse_checkout":"https://api.checkout402.com/c/chk_npD-wqTKN7B3ydxa/test","preview":"/r/egokiemute/clink/f/<path> serves file CONTENTS for any path (public repo)","how_to_buy":"pay clone_checkout with x402 (pay402 does it in one call); the goods arrive as payload_base64, a tar.gz of the full repo. Rehearse first at rehearse_checkout: same flow, simulated money.","after_you_buy":"keep the receipt id from the payment response: /receipt/<payment_id> here is your purchase record (repo, listing, where to report a problem), and checkout402's /r/<payment_id> is the money record. Tell your human both URLs."}