Skip to main content

API Documentation

Base URL

  • Development: http://localhost:8080
  • Production: https://your-api-domain.com

Authentication

Most endpoints require JWT authentication:

Authorization: Bearer <token>

Public Endpoints

GET /app-downloads

Returns app download links and "coming soon" flags for the public Download Apps page. No auth required.

Response:

{
"windows_shopkeeper_url": "https://...",
"android_customer_url": "https://...",
"ios_customer_url": "https://...",
"windows_coming_soon": false,
"android_coming_soon": false,
"ios_coming_soon": true
}

GET /delete-data

Serves a public HTML page for the Google Play "Delete data" link requirement (GDPR). Explains how users can delete their data (login and use Delete Account, or contact support).

POST /register

Register a new user.

Request:

{
"full_name": "John Doe",
"username": "johndoe",
"email": "john@example.com",
"phone": "+1234567890",
"password": "securepassword",
"role": "customer",
"shop_name": "My Shop",
"lat": 12.9716,
"long": 77.5946,
"address": "123 Main St"
}

POST /login

Login and receive JWT token.

Request:

{
"username": "johndoe",
"password": "securepassword"
}

Response:

{
"token": "eyJhbGciOiJIUzI1NiIs...",
"role": "customer",
"username": "johndoe"
}

POST /forgot-password

Request password reset email.

Request:

{
"email": "john@example.com"
}

POST /reset-password

Reset password using token.

Request:

{
"token": "reset-token-from-email",
"password": "newpassword"
}

Protected Endpoints

GET /profile

Get current user's profile.

Response:

{
"id": 1,
"username": "johndoe",
"full_name": "John Doe",
"email": "john@example.com",
"phone": "+1234567890",
"role": "customer",
"shop_name": null,
"address": null,
"is_open": false
}

PUT /profile

Update current user's profile.

Request:

{
"username": "newusername",
"address": "456 New St",
"password": "newpassword"
}

DELETE /profile

Delete the current user's account. Requires password confirmation.

Request:

{
"password": "currentpassword"
}

Response:

{
"message": "Account deleted successfully"
}

Notes:

  • Requires password confirmation for security
  • Deletes all associated data (files, reset tokens, payouts)
  • Nullifies payment order references (preserves financial records)
  • Clears authentication cookie
  • Admin accounts cannot be deleted through this endpoint

POST /upload

Upload a file for printing.

Supported file types: PDF (.pdf), images (.png, .jpg, .jpeg), Word (.doc, .docx), PowerPoint (.ppt, .pptx). Max 20MB per file, 100MB total per batch.

Headers: Authorization: Bearer <token>, Content-Type: multipart/form-data

Form Data:

  • files[] or file: File(s) to upload
  • print_type: "private" or "queue"
  • copies: Number of copies
  • print_mode: "single" or "double"
  • color_mode: "bw" or "color"
  • paper_size: "A4", "Letter", etc.
  • shop_id: Shopkeeper ID (required for queue prints)
  • comment: Optional customer notes

Response:

{
"file_id": 123,
"code": "aB3xY9",
"num_pages": 5,
"total_cost": 25.00,
"queue_position": 3
}

GET /file/:code

Download file by unique code.

Parameters:

  • code (path): 6-character unique code

GET /file/:code/status

Check file status.

Parameters:

  • code (path): 6-character unique code

Response:

{
"status": "uploaded"
}

GET /shops

Get nearest shopkeepers.

Query Params: lat, long (optional)

Response:

[
{
"id": 2,
"username": "shop1",
"shop_name": "Print Shop 1",
"lat": 12.9716,
"long": 77.5946,
"distance": 0.05,
"is_open": true,
"address": "123 Main St"
}
]

GET /queue

Get shopkeeper's print queue.

POST /calculate-cost

Calculate print cost before payment. Accepts the same file types as upload (PDF, images, Word, PPT). Send files as multipart/form-data with files[], copies, print_mode, color_mode, paper_size.

POST /create-payment-order

Create a payment order. Supports both Razorpay and Wallet payment methods.

Request:

{
"amount": 50.00,
"use_wallet": true,
"print_type": "private",
"copies": 1,
"print_mode": "single",
"color_mode": "bw",
"paper_size": "A4",
"shopkeeper_id": 123,
"comment": "Optional comment",
"platform_commission": 0.0
}

Request Fields:

  • amount (required): Payment amount in INR
  • use_wallet (optional): Boolean to enable wallet payment if sufficient balance
  • print_type (required): "private" or "queue"
  • copies (optional): Number of copies (default: 1)
  • print_mode (optional): "single" or "double" (default: "single")
  • color_mode (optional): "bw" or "color" (default: "bw")
  • paper_size (optional): Paper size (default: "A4")
  • shopkeeper_id (required for queue prints): Shopkeeper user ID
  • comment (optional): Customer notes
  • platform_commission (optional): Platform commission percentage (0-1, default: 0)

Response:

{
"id": 123,
"order_id": "order_xxx",
"amount": 50.00,
"status": "paid",
"payment_method": "wallet",
"wallet_amount": 50.00,
"razorpay_amount": 0.00,
"key_id": "rzp_test_xxx",
"shopkeeper_id": 123,
"shopkeeper_amount": 50.00,
"skip_payment": true
}

Payment Methods:

  • "wallet": Full payment from wallet (instant, no Razorpay needed)
  • "razorpay": Payment via Razorpay gateway
  • "hybrid": Partial wallet + Razorpay payment

Payment Flow:

  1. If use_wallet is true, system checks wallet balance
  2. Sufficient balance: Deducts from wallet, sets payment_method: "wallet", skip_payment: true
  3. Insufficient balance: Creates Razorpay order, sets payment_method: "razorpay"
  4. Partial balance: Deducts wallet portion, creates Razorpay order for remainder, sets payment_method: "hybrid"

GET /payment-order/:orderId/status

Check payment status.

Parameters:

  • orderId (path): Payment order ID

Response:

{
"id": 123,
"user_id": 1,
"order_id": "order_xxx",
"payment_id": "pay_xxx",
"amount": 50.00,
"status": "paid",
"payment_method": "wallet",
"wallet_amount": 50.00,
"created_at": "2024-01-17T20:00:00Z",
"paid_at": "2024-01-17T20:00:01Z"
}

POST /payment/webhook

Razorpay webhook endpoint (public, signature verified). Handles payment confirmations and wallet top-ups.

GET /csrf-token

Get CSRF token for state-changing requests.

Response:

{
"csrfToken": "token-string"
}

POST /logout

Logout and clear authentication cookie.

POST /forgot-username

Request username recovery email.

Request:

{
"email": "john@example.com"
}

POST /file/:code/confirm

Confirm private print download (shopkeeper use).

GET /queue/:orderGroupId/files

Get files for a specific order group in the queue.

GET /queue/download/:fileId

Download a specific file from the queue (shopkeeper use).

POST /queue/:fileId/confirm

Confirm queue print completion.

GET /my-files

Get current user's uploaded files.

GET /my-orders

Get current user's payment orders (for customer order history).

GET /shop/history

Get shop's print history (shopkeeper use).

POST /shop/status

Toggle shop open/closed status.

Request:

{
"is_open": true
}

POST /shop/heartbeat

Shopkeeper app sends a heartbeat to keep the shop marked as "open". Used with the backend sweeper: if both app heartbeat and web activity are stale, the shop is auto-closed. No request body required.

POST /withdraw/:fileId

Withdraw a print job and receive refund.

GET /shopkeeper/payouts

Get shopkeeper's payout history.

Wallet Service Endpoints

The wallet service is implemented. Customers can pre-load money, pay instantly (wallet or hybrid with Razorpay), and receive instant refunds on withdrawal.

GET /wallet/balance

Get current wallet balance for the authenticated user.

Response:

{
"balance": 500.00
}

POST /wallet/topup

Add money to wallet via Razorpay.

Request:

{
"amount": 500.00
}

Request Fields:

  • amount (required): Top-up amount in INR (minimum: ₹10, maximum: ₹10,000)

Response:

{
"order_id": "order_xxx",
"key_id": "rzp_test_xxx",
"amount": 500.00
}

Flow:

  1. Creates Razorpay payment order for top-up
  2. After successful payment (via webhook), adds amount to wallet balance
  3. Creates wallet transaction record

GET /wallet/transactions

Get wallet transaction history.

Query Parameters:

  • limit (optional): Number of transactions to return (default: 50, max: 100)
  • offset (optional): Pagination offset (default: 0)

Response:

{
"transactions": [
{
"id": 1,
"type": "topup",
"amount": 500.00,
"balance_before": 0.00,
"balance_after": 500.00,
"status": "completed",
"description": "Wallet top-up",
"created_at": "2024-01-17T20:00:00Z"
},
{
"id": 2,
"type": "payment",
"amount": -50.00,
"balance_before": 500.00,
"balance_after": 450.00,
"status": "completed",
"description": "Print payment",
"payment_order_id": 123,
"created_at": "2024-01-17T21:00:00Z"
},
{
"id": 3,
"type": "refund",
"amount": 50.00,
"balance_before": 450.00,
"balance_after": 500.00,
"status": "completed",
"description": "Refund for withdrawal",
"payment_order_id": 123,
"created_at": "2024-01-17T22:00:00Z"
}
],
"total": 25
}

Transaction Types:

  • "topup": Money added to wallet
  • "payment": Money spent from wallet
  • "refund": Money refunded to wallet
  • "withdrawal": Money withdrawn from wallet (optional feature)

POST /wallet/withdraw (Optional)

Withdraw wallet balance to bank account. Requires bank account verification.

Request:

{
"amount": 200.00,
"bank_account": "1234567890",
"ifsc_code": "BANK0001234",
"account_holder_name": "John Doe"
}

Response:

{
"withdrawal_id": 123,
"status": "pending",
"amount": 200.00,
"processing_time": "2-3 business days"
}

Wallet Service Implementation Details

Database Schema

Users Table Update

ALTER TABLE users ADD COLUMN wallet_balance DECIMAL(10,2) DEFAULT 0.00;

Wallet Transactions Table

CREATE TABLE wallet_transactions (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users(id) NOT NULL,
transaction_type TEXT NOT NULL,
amount DECIMAL(10,2) NOT NULL,
balance_before DECIMAL(10,2) NOT NULL,
balance_after DECIMAL(10,2) NOT NULL,
payment_order_id INT REFERENCES payment_orders(id),
razorpay_payment_id TEXT,
razorpay_refund_id TEXT,
status TEXT DEFAULT 'completed',
description TEXT,
created_at TIMESTAMP DEFAULT NOW()
);

Payment Orders Table Update

ALTER TABLE payment_orders ADD COLUMN payment_method TEXT DEFAULT 'razorpay';
ALTER TABLE payment_orders ADD COLUMN wallet_amount DECIMAL(10,2) DEFAULT 0.00;

Payment Flow with Wallet

Scenario A: Full Wallet Payment

1. Customer creates payment order with use_wallet: true
2. System checks wallet balance (e.g., ₹200)
3. Payment amount: ₹50
4. Balance sufficient → Deducts ₹50 from wallet
5. Payment order status: "paid" (immediate)
6. skip_payment: true (no Razorpay checkout needed)
7. File can be uploaded immediately

Scenario B: Insufficient Wallet Balance

1. Customer creates payment order with use_wallet: true
2. System checks wallet balance (e.g., ₹30)
3. Payment amount: ₹50
4. Balance insufficient → Creates Razorpay order for ₹50
5. Customer pays via Razorpay
6. Payment order status: "paid" (after webhook)
7. File can be uploaded

Scenario C: Hybrid Payment (Partial Wallet)

1. Customer creates payment order with use_wallet: true
2. System checks wallet balance (e.g., ₹30)
3. Payment amount: ₹50
4. Deducts ₹30 from wallet
5. Creates Razorpay order for remaining ₹20
6. Customer pays ₹20 via Razorpay
7. Payment order status: "paid" (after webhook)
8. payment_method: "hybrid", wallet_amount: 30.00, razorpay_amount: 20.00

Refund Flow with Wallet

When a customer withdraws a print job:

If payment was via wallet:

  • Refund goes to wallet instantly
  • Balance updated immediately
  • No Razorpay refund needed

If payment was via Razorpay:

  • Refund via Razorpay (5-7 business days)
  • Or customer can choose wallet refund (instant)

Wallet Limits

  • Minimum Top-up: ₹10
  • Maximum Top-up: ₹10,000 per transaction
  • Maximum Wallet Balance: ₹50,000 (optional limit)
  • Minimum Withdrawal: ₹100 (if withdrawal enabled)

Security Considerations

  • Wallet balance cannot go negative
  • All transactions are logged in wallet_transactions table
  • Database transactions ensure atomicity
  • Row-level locking prevents race conditions
  • Rate limiting on top-ups (prevent abuse)
  • Server-side validation of all amounts

Admin Endpoints

All admin endpoints require admin role and (optional) IP whitelist when ALLOWED_ADMIN_IPS is set. CSRF required for state-changing requests.

GET /admin/dashboard/stats

Get dashboard statistics.

GET /admin/users

Get all users (paginated).

GET /admin/users/details

Get detailed info for a specific user (e.g. for admin user management).

POST /admin/users/delete

Delete a user account (admin-initiated). Request body: { "user_id": 123 }.

GET /admin/orders

Get all payment orders.

GET /admin/payouts

Get all shopkeeper payouts.

PUT /admin/payouts/update

Update a single payout status.

PUT /admin/payouts/bulk-update

Bulk update payout statuses.

GET /admin/payouts/export

Export payouts (e.g. CSV).

PUT /admin/app-downloads

Update app download links and "coming soon" flags (Windows shopkeeper, Android customer, iOS customer). These appear on the public Download Apps page.

Request:

{
"windows_shopkeeper_url": "https://...",
"android_customer_url": "https://...",
"ios_customer_url": "https://...",
"windows_coming_soon": false,
"android_coming_soon": false,
"ios_coming_soon": true
}

For a quick reference, see the API Reference.