The Bitcoin Blockchain Spreadsheet API provides endpoints for HandCash authentication, user profile management, and spreadsheet operations. The API is built with Node.js/Express and deployed on Vercel.
Base URLs:
- Development:
http://localhost:3001 - Production:
https://bitcoin-spreadsheet-api.vercel.app
API Version: 1.0
Authentication: HandCash OAuth 2.0
Content Type: application/json
The API uses HandCash OAuth 2.0 for authentication. The flow involves redirecting users to HandCash for authorization and receiving an auth token.
sequenceDiagram
participant C as Client
participant A as API
participant H as HandCash
C->>A: GET /api/auth/handcash/url
A->>C: Return authUrl
C->>H: Redirect to authUrl
H->>A: Callback with authToken
A->>H: Fetch user profile
H->>A: Return profile data
A->>C: Redirect with userData
GET /api/health
Check API server status and configuration.
{
"status": "ok",
"appId": "68c532b2a0b054ff147f4579",
"hasSecret": true
}curl -X GET http://localhost:3001/api/healthGET /api/auth/handcash/url
Generate HandCash OAuth authorization URL for user login.
{
"authUrl": "https://app.handcash.io/#/authorizeApp?appId=68c532b2a0b054ff147f4579"
}curl -X GET http://localhost:3001/api/auth/handcash/url{
"error": "Failed to generate auth URL"
}GET /api/auth/handcash/callback
Handle OAuth callback from HandCash with authorization token.
| Parameter | Type | Required | Description |
|---|---|---|---|
| authToken | string | Yes | Authorization token from HandCash |
Redirects to client URL with user data:
https://yourapp.com?userData=<base64-encoded-user-data>
Redirects to client URL with error:
https://yourapp.com?error=authentication_failed
# This endpoint is called by HandCash, not directly by clients
GET /api/auth/handcash/callback?authToken=abc123xyz789GET /api/auth/handcash/profile
Get authenticated user's profile information.
Authorization: Bearer <authToken>
{
"handle": "bitcoin.spreadsheet",
"paymail": "bitcoin.spreadsheet@handcash.io",
"displayName": "Bitcoin Spreadsheet",
"avatarUrl": "https://handcash.io/avatar/bitcoin.spreadsheet"
}// No auth token
{
"error": "No auth token provided"
}
// Invalid/expired token
{
"error": "Failed to get profile"
}
// Demo mode (no app secret)
{
"handle": "demo_user",
"paymail": "demo@handcash.io",
"displayName": "Demo User",
"avatarUrl": "https://handcash.io/avatar/default"
}curl -X GET http://localhost:3001/api/auth/handcash/profile \
-H "Authorization: Bearer your-auth-token"POST /api/handcash-profile
Get authenticated user's profile information using POST method.
{
"authToken": "string"
}{
"success": true,
"profile": {
"handle": "bitcoin.spreadsheet",
"paymail": "bitcoin.spreadsheet@handcash.io",
"displayName": "Bitcoin Spreadsheet",
"avatarUrl": "https://handcash.io/avatar/bitcoin.spreadsheet",
"publicKey": "02a1b2c3d4e5f6...",
"email": "user@example.com",
"phoneNumber": "+1234567890"
}
}{
"error": "Failed to get profile",
"details": "Invalid auth token"
}{
"success": true,
"profile": {
"handle": "demo_user",
"paymail": "demo@handcash.io",
"displayName": "Demo User",
"avatarUrl": null
}
}curl -X POST http://localhost:3001/api/handcash-profile \
-H "Content-Type: application/json" \
-d '{"authToken": "your-auth-token"}'The BitcoinService class provides client-side blockchain and encryption functionality.
Initialize connection to HandCash wallet.
const bitcoinService = new BitcoinService();
await bitcoinService.connect();Create a new spreadsheet.
const spreadsheet = await bitcoinService.createSpreadsheet("My Spreadsheet");Update a cell with encrypted data.
await bitcoinService.updateCell("sheet_123", 0, 0, "Hello World", "string");Retrieve and decrypt cell data.
const cell = await bitcoinService.getCell("sheet_123", 0, 0);Calculate formula results.
const result = await bitcoinService.calculateFormula("=SUM(A1:A5)", cells);Get wallet balance in BSV.
const balance = await bitcoinService.getBalance(); // "0.00100000"Get wallet address or paymail.
const address = await bitcoinService.getAddress(); // "user@handcash.io"The HandCashAuthService class handles OAuth authentication with HandCash.
Start OAuth login flow (redirects to HandCash).
const authService = new HandCashAuthService();
await authService.login();Handle OAuth callback from HandCash.
const user = await authService.handleCallback(window.location.href);Clear user session and logout.
authService.logout();Check if user is authenticated.
if (authService.isAuthenticated()) {
// User is logged in
}Get current user information.
const user = authService.getCurrentUser();
if (user) {
console.log(`Hello, @${user.handle}!`);
}interface SpreadsheetData {
id: string;
title: string;
cells: { [key: string]: CellData };
owner: string;
publicKey?: string;
}interface CellData {
row: number;
col: number;
value: string;
dataType: 'number' | 'string' | 'formula';
lastUpdated: number;
encrypted?: boolean;
}interface HandCashUser {
handle: string;
paymail: string;
publicKey?: string;
avatarUrl?: string;
displayName?: string;
}interface AuthTokens {
accessToken: string;
refreshToken?: string;
expiresIn?: number;
tokenType?: string;
}200- Success400- Bad Request (missing parameters)401- Unauthorized (invalid/missing auth token)404- Not Found (invalid endpoint)500- Internal Server Error
{
"error": "Error message",
"details": "Additional error details (optional)"
}{
"error": "No auth token provided"
}{
"error": "Failed to get profile",
"details": "HandCash API returned 401"
}{
"error": "No HandCash secret configured, returning demo data"
}Currently no rate limiting is implemented, but it will be added in production:
- Development: No limits
- Production: 100 requests per 15 minutes per IP
{
origin: '*', // Allow all origins
credentials: true
}{
origin: ['https://bitcoin-spreadsheet.vercel.app'],
credentials: true
}# HandCash App Configuration
HANDCASH_APP_ID=your_app_id
HANDCASH_APP_SECRET=your_app_secret
# Client Configuration
CLIENT_URL=https://your-frontend-domain.com
# Server Configuration
PORT=3001# Development overrides
REACT_APP_HANDCASH_APP_ID=your_dev_app_id
REACT_APP_HANDCASH_APP_SECRET=your_dev_app_secret- Use HTTPS in production
- Validate all inputs
- Implement rate limiting
- Add proper CORS configuration
- Use security headers (Helmet.js)
- Store tokens securely
- Implement token expiration
- Use secure session management
- Validate tokens on each request
- Encrypt sensitive data
- Use secure key derivation
- Implement proper access controls
- Audit data access patterns
# Health check
curl http://localhost:3001/api/health
# Get auth URL
curl http://localhost:3001/api/auth/handcash/url
# Test profile endpoint
curl -X POST http://localhost:3001/api/handcash-profile \
-H "Content-Type: application/json" \
-d '{"authToken": "test-token"}'# Run API tests
cd api
npm test
# Run integration tests
npm run test:integrationPOST /api/spreadsheets- Create spreadsheetGET /api/spreadsheets/:id- Get spreadsheetPUT /api/spreadsheets/:id/cells/:cellId- Update cellGET /api/spreadsheets/:id/cells- Get all cellsPOST /api/spreadsheets/:id/share- Share spreadsheetGET /api/users/me- Get current userPOST /api/formulas/calculate- Calculate formulas
- WebSocket support for real-time collaboration
- File upload/download endpoints
- Bulk operations
- Advanced authentication (JWT)
- API versioning
- GraphQL support
import { BitcoinSpreadsheetAPI } from '@bitcoin-spreadsheet/sdk';
const api = new BitcoinSpreadsheetAPI({
baseUrl: 'https://api.bitcoin-spreadsheet.com',
authToken: 'your-token'
});
const spreadsheet = await api.spreadsheets.create('My Sheet');
await api.cells.update(spreadsheet.id, 0, 0, 'Hello World');- Python SDK
- Go SDK
- REST API client generators (OpenAPI)
API Documentation Version: 1.0
Last Updated: December 2024
Next Review: January 2025