This is the backend API for SendXpress — a social commerce platform where importers discover products from global suppliers, negotiate in real-time chat, and pay safely through smart contract escrow on Stellar.
The API handles user management, social feed, marketplace listings, real-time chat, and orchestrates Stellar transactions for the escrow deal lifecycle.
Related repos:
- SendXpress/mobile — SwiftUI iOS app
- SendXpress/smartcontract — Soroban escrow contract
| Layer | Technology | Why |
|---|---|---|
| Runtime | Node.js 20 | Fast, lightweight, huge ecosystem |
| Framework | Express 4 | Minimal, well-understood REST framework |
| Database | Supabase (Postgres) | Instant setup, Realtime for chat, Row Level Security, image storage |
| Blockchain | Stellar SDK | Horizon API for accounts/balances, transaction building for escrow |
| Auth | Stellar wallet signature | Challenge-response verification against Ed25519 public key |
| Method | Route | Description |
|---|---|---|
POST |
/api/users |
Create or find user by Stellar wallet address |
GET |
/api/users/:wallet |
Fetch user profile |
PATCH |
/api/users/:id/role |
Set buyer or seller role |
| Method | Route | Description |
|---|---|---|
GET |
/api/posts |
Fetch posts with user join (newest first) |
POST |
/api/posts |
Create a new post (text, image, tagged listing) |
POST |
/api/posts/:id/like |
Toggle like on a post |
| Method | Route | Description |
|---|---|---|
GET |
/api/listings |
Fetch active listings with seller info |
POST |
/api/listings |
Create a listing (seller role required) |
GET |
/api/listings/:id |
Fetch single listing detail |
| Method | Route | Description |
|---|---|---|
GET |
/api/chat/conversations |
Fetch conversations for a user |
POST |
/api/chat/conversations |
Create or find a conversation for a listing |
GET |
/api/chat/messages |
Fetch messages in a conversation |
POST |
/api/chat/messages |
Send a message + update conversation timestamp |
| Method | Route | Description |
|---|---|---|
POST |
/api/deals |
Create escrow deal — build Stellar tx, lock XLM, store in DB |
GET |
/api/deals |
Fetch deals for a user (as buyer or seller) |
POST |
/api/deals/:id/ship |
Seller marks deal as shipped |
POST |
/api/deals/:id/confirm |
Buyer confirms receipt — release funds via Stellar tx |
POST |
/api/deals/:id/dispute |
Either party raises a dispute |
POST |
/api/deals/:id/cancel |
Buyer cancels before shipment — refund via Stellar tx |
backend/
├── package.json
├── .env.example
└── src/
├── index.js Entry point — Express app, route mounting
│
├── config/
│ ├── supabase.js Supabase client (Postgres + Realtime)
│ └── stellar.js Horizon server + network passphrase
│
├── routes/
│ ├── users.js User CRUD + role assignment
│ ├── posts.js Social feed + likes
│ ├── listings.js Marketplace CRUD
│ ├── chat.js Conversations + messages
│ └── deals.js Full escrow deal lifecycle
│
├── services/
│ └── escrow.js Stellar transaction builders
│ (lockFunds, releaseFunds, refund)
│
├── middleware/
│ └── auth.js Wallet signature verification
│
└── tests/ Test directory
- Node.js 20+
- A Supabase project (free tier works) — supabase.com
- Stellar testnet access (no account needed — uses Horizon public API)
git clone https://github.com/SendXpress/backend.git
cd backend
cp .env.example .envFill in your .env:
PORT=3000
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_KEY=your-anon-key
STELLAR_NETWORK=testnet
STELLAR_HORIZON=https://horizon-testnet.stellar.org
ESCROW_SECRET_KEY=S_YOUR_ESCROW_ACCOUNT_SECRETnpm install
npm run dev # starts with --watch for auto-reloadcurl http://localhost:3000/api/health
# → {"status":"ok"}The escrow.js service builds and submits Stellar transactions for the deal lifecycle:
| Function | What it does |
|---|---|
lockFunds(buyerSecret, escrowPublic, amount, memo) |
Buyer sends XLM to the escrow holding account |
releaseFunds(escrowSecret, sellerPublic, amount, memo) |
Escrow releases XLM to the seller on confirmation |
refund(escrowSecret, buyerPublic, amount, memo) |
Escrow returns XLM to buyer on cancellation |
All transactions use Stellar's native XLM with the deal ID as a memo for traceability.
The API expects these Supabase tables (create via SQL editor):
| Table | Key columns |
|---|---|
users |
id, wallet, handle, display_name, avatar_url, role, created_at |
posts |
id, user_id, text, image_url, tagged_listing_id, likes_count, created_at |
listings |
id, seller_id, title, description, price, category, moq, ship_days, image_url, status |
conversations |
id, listing_id, buyer_id, seller_id, last_message, last_at |
messages |
id, conversation_id, sender_id, type, body, offer_amount, offer_status, created_at |
deals |
id, buyer, seller, amount, description, status, created_at |
MIT