Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

193 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Settley Send

Settley Send is rail-agnostic payment and claim infrastructure for cross-border support money. A sender creates a transfer in Telegram, pays through the live funding rail for that payment, and receives a claim code/link that the recipient can use to choose a payout method.

Base USDC is the live wallet-funding rail today. Solana and additional rails are planned next, but they are not live payment options yet.

What Works Today

  • Telegram sender intake with natural-language parsing and a button-based transfer form.
  • FX estimates for supported destination currencies before the sender pays.
  • PAY-... payment references for sender funding.
  • Deterministic deposit-address support for the live funding rail. In production today, that means Base USDC.
  • Strict payment detection with exact amount matching, expiry checks, tx-hash reuse protection, underpayment handling, and manual review for unsafe cases.
  • Over-$200 identity review with age validation, restricted-jurisdiction controls, uploaded ID evidence, local OCR name/DOB matching, and OpenSanctions screening.
  • STL-... claim codes and claim links for receivers.
  • Live receiver payout methods:
    • Supported African payout corridors, loaded dynamically from the active payout provider's coverage API.
    • Bank payout where the corridor supports BANK.
    • EVM wallet payout.
  • Visible but not live in this deployment:
    • Mobile money.
    • Airtime.
    • Virtual card.

User Codes

  • PAY-...: sender payment reference. This identifies the pending payment and the deposit address for the live rail selected by the product. Today that rail is Base USDC.
  • STL-...: receiver claim code. This is generated only after payment is detected and can be shared by Telegram, email, or copy/paste.
  • Receiver PIN: optional. A PIN only blocks payout when claim metadata explicitly has requireClaimPin === "true".

Sender Happy Paths

  • Under-$200 transfer:

    1. Sender opens @settleysendbot.
    2. Sender enters amount, destination, recipient name, and sender display name.
    3. Bot shows FX estimate.
    4. Sender confirms.
    5. Bot creates a PAY-... reference and payment link.
    6. Sender sends the exact amount on the payment page's live rail. Today that is USDC on Base.
    7. Bot detects payment and generates an STL-... claim code/link.
  • Over-$200 transfer:

    1. Same quote flow as above.
    2. Bot pauses before payment link creation.
    3. Sender provides legal name, DOB, country of residence, government ID number, and an uploaded ID image.
    4. Bot validates age and jurisdiction.
    5. Bot runs OCR matching against name/DOB and screens through OpenSanctions.
    6. If clear and matched, bot unlocks the payment link. Today that link asks for Base USDC.
    7. If unclear, the transfer remains pending manual review.
  • Funded payment recovery:

    1. Sender has a funded PAY-... reference but no delivered claim code.
    2. Bot can recover/generate the STL-... code from the funded payment.

Receiver Happy Paths

  • Bank payout:

    1. Receiver opens the claim link or types /claim STL-....
    2. Receiver chooses bank payout when the destination corridor supports BANK.
    3. Receiver enters bank name and account number.
    4. Payout-provider account lookup verifies or presents the account details for confirmation.
    5. Bot locks the claim, initiates the provider payout, sends the partner deposit, and waits for webhook status.
    6. The payout webhook marks the claim settled on success and the bot notifies sender and receiver.
  • Wallet payout:

    1. Receiver claims STL-....
    2. Receiver chooses crypto wallet.
    3. Receiver enters a valid EVM 0x... address.
    4. Bot transfers the held funds onchain and marks the claim settled.

Unhappy Paths And Controls

  • Wrong network or token: not treated as a normal payment. Funds are ledgered where detected and routed to reconciliation/recovery instead of blindly crediting or refunding.
  • Underpayment: bot reports the partial amount seen and the remaining amount needed.
  • Overpayment: accepted only in attended scans when the payer matches the expected wallet; excess remains recoverable through the recorded transfer plan.
  • Expired unpaid payment: PAY-... is marked expired and the sender must start again.
  • Late payment after expiry: recent expired payments can be revived to funded if the matching onchain payment arrives.
  • Duplicate transaction hash: one source transaction cannot fund two claims.
  • Sweep failure from deterministic deposit vault: payment is held for operator review before claim-code issuance.
  • Missing payer wallet or missing refund transfer breakdown: refund is queued for manual reconciliation.
  • Sender refund before claim-code generation: funded PAY-... payments can be refunded to the recorded payer wallet when the transfer plan is available.
  • Payment already generated a claim code: automatic sender refund is blocked; operator review is required.
  • Provider bank payout failure: claim returns to funded, so the receiver can retry bank details or choose another live payout method.
  • Provider webhook success: claim moves to settled and notifications are sent.
  • Compliance underage/restricted jurisdiction/blocked watchlist: transfer is blocked before payment link creation.
  • Compliance OCR mismatch, unreadable document, OpenSanctions error, or ambiguous result: transfer stays in manual review.

Architecture

Telegram sender
  -> transfer intake + FX estimate
  -> compliance gate when required
  -> PAY- reference + live-rail payment link
  -> deterministic deposit address
  -> scanner confirms exact payment
  -> STL- claim code/link
  -> receiver chooses bank or wallet payout
  -> payout webhook or onchain payout settles the claim

Tech Stack

  • Node.js and TypeScript.
  • Telegraf for Telegram.
  • Supabase for claims, sessions, compliance profiles, deposits, and document metadata.
  • Supabase Storage for private ID document uploads.
  • tesseract.js for local OCR.
  • OpenSanctions for sanctions/watchlist screening.
  • Viem for EVM reads/transfers.
  • Active payout provider for live African payout coverage, payout initiation, and webhook settlement.

Environment

Var Purpose
TELEGRAM_BOT_TOKEN Telegram bot token from BotFather.
OPENAI_BASE_URL / OPENAI_API_KEY / OPENAI_MODEL Optional LLM intent parsing.
MAX_USD Per-transfer safety cap.
DAPP_URL Public frontend origin for payment links.
PAY_API_BASE_URL Backend API origin used by payment pages.
DIRECT_PAYMENT_ASSET Live sender funding asset. Use base:usdc for today's production rail.
DEPOSIT_FACTORY_BASE_ADDRESS Base deterministic deposit factory. Required for today's Base USDC copy-address payments.
EVM_ESCROW_WALLET Settlement wallet used by scanners and payouts.
AUTO_REFUND_UNMATCHED_DEPOSITS Keep false unless recovery policy and gas are ready.
SWITCH_SERVICE_KEY Switch service key for bank payouts.
SWITCH_WEBHOOK_SECRET HMAC secret for Switch webhook verification.
SWITCH_ASSET Partner payout deposit asset, currently base:usdc.
OPENSANCTIONS_API_KEY OpenSanctions API key.
OPENSANCTIONS_DATASET OpenSanctions dataset, default default.
OPENSANCTIONS_MIN_SCORE Screening threshold, default 0.7.
COMPLIANCE_DOCUMENT_BUCKET Private Supabase Storage bucket for ID uploads.
COMPLIANCE_MAX_UPLOAD_MB Max ID image size.
COMPLIANCE_DOCUMENT_RETENTION_DAYS Retention window for uploaded ID files.
COMPLIANCE_OCR_LANG Tesseract OCR language, default eng.
SUPABASE_URL / SUPABASE_SERVICE_ROLE_KEY Supabase database and storage access.
ADMIN_USERNAME / ADMIN_PASSWORD Basic auth for admin routes.

Admin And Recovery APIs

  • POST /api/admin/compliance/review: approve, reject, or block a pending compliance profile.
  • GET /api/admin/claims: list recent claims.
  • POST /api/admin/refund: refund a claim to the recorded payer or an admin-provided recipient.
  • GET /api/admin/deposits: list unmatched deposits.
  • POST /api/admin/refund-deposit: refund an unmatched deposit.
  • POST /api/admin/deposits/issue-claim: issue a claim code from an unmatched deposit.
  • POST /api/admin/recover-stuck: reset stale paying/refunding claims.

Local Development

npm install
cp .env.example .env
npm run typecheck
npm test
npm start

Static marketing/payment pages live in public/. The backend serves API routes plus Telegram and payout-provider webhooks.

Deployment Notes

  • Backend bot runtime deploys to Fly.
  • Public pages deploy to Cloudflare Pages.
  • Apply Supabase migrations before enabling document upload in production.
  • Create the private compliance-documents storage bucket through the migration.
  • Do not expose SUPABASE_SERVICE_ROLE_KEY to any public frontend.

Compliance Description

Settley Send runs risk-based identity review and sanctions screening. For over-threshold transfers it collects identity details, asks for uploaded ID evidence, uses local OCR to compare document text with the provided name and DOB, checks age and jurisdiction, and screens through OpenSanctions.

This is not full vendor KYC. It does not yet include liveness, selfie matching, document authenticity checks, proof of address, or a third-party identity verification vendor.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages