진보 JINBO API Documentation

World-Class Coaching Platform API • Version 2.2.0

🔐 API KEY SYSTEM - COMPLETE EXPLANATION

For Business Integrations Like "WE ARE HYBRID. IN"
Date: October 2, 2025


🎯 HOW IT ALL WORKS

The Complete Flow

1. Business Owner (admin@legacy-integration.cloud) logs into JINBO
2. Creates brand: "WE ARE HYBRID. IN" 
3. Gets API key: jinbo_live_abc123...
4. Uses API key to:
   ✅ Create classes programmatically
   ✅ Invite/assign coaches
   ✅ Enroll students
   ✅ Track progress
   ✅ Access analytics

🔑 TWO AUTHENTICATION OPTIONS

Option 1: JWT Token (Human Users)

When to use: Interactive sessions, web dashboard, mobile app

// 1. User logs in
POST https://legacy-integration.cloud/auth/login
{
  "email": "admin@legacy-integration.cloud",
  "password": "secure_password"
}

// 2. Get JWT token
Response: { "token": "eyJhbGc..." }

// 3. Use token in API calls
GET https://jinbo.life/api/classes
Headers: { "Authorization": "Bearer eyJhbGc..." }

Pros:

Cons:


Option 2: API Key (Server-to-Server)

When to use: Automation, integrations, scripts, cron jobs

// 1. Generate API key (one-time)
POST https://jinbo.life/api/auth/api-key
Headers: { "Authorization": "Bearer JWT_TOKEN" }
Body: {
  "name": "WE ARE HYBRID Production Key",
  "scopes": ["classes:write", "coaches:write", "students:write"]
}

// 2. Get API key (save it!)
Response: { "api_key": "jinbo_live_1234567890abcdef..." }

// 3. Use API key forever
GET https://jinbo.life/api/classes
Headers: { "X-API-Key": "jinbo_live_1234567890abcdef..." }

Pros:

Cons:


🏗️ DATABASE STRUCTURE

Brands Table (Your Business)

CREATE TABLE brands (
    id UUID PRIMARY KEY,
    name VARCHAR(255),              -- "WE ARE HYBRID. IN"
    domain VARCHAR(255),            -- "wearehybrid.in"
    owner_email VARCHAR(255),       -- "admin@legacy-integration.cloud"
    settings JSONB,                 -- Timezone, currency, etc.
    created_at TIMESTAMP
);

API Keys Table (Your Authentication)

CREATE TABLE api_keys (
    id UUID PRIMARY KEY,
    brand_id UUID,                  -- Links to brands table
    key_hash VARCHAR(64),           -- SHA-256 hash (secure!)
    name VARCHAR(255),              -- "Production API Key"
    scopes JSONB,                   -- ["classes:write", "students:read"]
    created_at TIMESTAMP,
    last_used_at TIMESTAMP,         -- Track usage
    expires_at TIMESTAMP,           -- Optional expiration
    revoked_at TIMESTAMP            -- Soft delete
);

Security: We NEVER store the actual API key in plain text, only SHA-256 hash!

Classes Table (Your Coaching Sessions)

CREATE TABLE classes (
    id UUID PRIMARY KEY,
    brand_id UUID,                  -- Your brand
    name VARCHAR(255),              -- "Yoga for Beginners"
    description TEXT,
    skill_id UUID,                  -- What skill (yoga, pilates, etc.)
    level VARCHAR(50),              -- beginner/intermediate/advanced
    max_students INTEGER,           -- Class capacity
    duration_minutes INTEGER,       -- Session length
    coach_id UUID,                  -- Assigned coach
    location_id UUID,               -- Where it happens
    schedule JSONB,                 -- Recurring schedule
    pricing JSONB,                  -- Price info
    status VARCHAR(50),             -- active/deleted
    created_at TIMESTAMP
);

Class Enrollments (Students in Classes)

CREATE TABLE class_enrollments (
    id UUID PRIMARY KEY,
    class_id UUID,                  -- Which class
    student_id UUID,                -- Which student
    status VARCHAR(50),             -- active/inactive/completed
    enrolled_at TIMESTAMP,
    UNIQUE(class_id, student_id)    -- Can't enroll twice
);

🔐 HOW AUTHENTICATION WORKS

Request Flow

1. Request comes in
   ↓
2. Check for X-API-Key header
   ↓
3. If API key present:
   - Hash the key (SHA-256)
   - Look up in api_keys table
   - Verify not revoked/expired
   - Get brand_id
   - Set req.user and req.brandId
   ↓
4. If no API key, check Authorization header
   - Extract JWT token
   - Validate with Legacy Integration
   - Get user info
   - Set req.user and req.brandId
   ↓
5. If neither: return 401 Unauthorized
   ↓
6. Check permissions (role + scopes)
   ↓
7. Execute request with brand context

Code: Authentication Middleware

// File: src/api/middleware/api-key-auth.js

function apiKeyAuth(db) {
  return async (req, res, next) => {
    const apiKey = req.headers['x-api-key'];
    
    if (!apiKey) {
      return next(); // Try JWT auth instead
    }
    
    // Hash the provided key
    const keyHash = crypto
      .createHash('sha256')
      .update(apiKey)
      .digest('hex');
    
    // Look up in database
    const result = await db.query(`
      SELECT 
        ak.id, ak.brand_id, ak.scopes,
        b.name as brand_name, b.owner_email
      FROM api_keys ak
      JOIN brands b ON ak.brand_id = b.id
      WHERE ak.key_hash = $1
        AND ak.revoked_at IS NULL
        AND (ak.expires_at IS NULL OR ak.expires_at > NOW())
    `, [keyHash]);
    
    if (result.rows.length === 0) {
      return res.status(401).json({
        error: 'Invalid API key'
      });
    }
    
    // Set user context
    const keyData = result.rows[0];
    req.user = {
      id: `api_key_${keyData.id}`,
      email: keyData.owner_email,
      name: keyData.brand_name,
      role: 'admin',              // API keys get admin access
      brand_id: keyData.brand_id,
      api_key_scopes: keyData.scopes,
      auth_method: 'api_key'
    };
    
    req.brandId = keyData.brand_id;
    
    next();
  };
}

🎨 SCOPE-BASED PERMISSIONS

Available Scopes

const AVAILABLE_SCOPES = {
  // Classes
  'classes:read': 'View classes',
  'classes:write': 'Create/update/delete classes',
  
  // Coaches
  'coaches:read': 'View coaches',
  'coaches:write': 'Invite/assign coaches',
  
  // Students
  'students:read': 'View students',
  'students:write': 'Add/enroll students',
  
  // Sessions
  'sessions:read': 'View sessions',
  'sessions:write': 'Create/track sessions',
  
  // Analytics
  'analytics:read': 'View reports',
  
  // Wildcard (full access)
  '*': 'Full access to everything'
};

Checking Scopes in Routes

// File: src/api/routes/classes.js

router.post('/classes', 
  requireAuth,                      // Must be authenticated
  requireRole('admin'),             // Must have admin role (if JWT)
  requireScope('classes:write'),    // Must have this scope (if API key)
  async (req, res) => {
    // Create class logic
  }
);

How it works:


📝 COMPLETE EXAMPLE: WE ARE HYBRID. IN

Step 1: Create the Brand

# 1. Login as admin@legacy-integration.cloud
curl -X POST https://legacy-integration.cloud/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "admin@legacy-integration.cloud",
    "password": "your_password"
  }'

# Response: { "token": "eyJhbGc..." }

Step 2: Register Business in JINBO

# 2. Create brand
curl -X POST https://jinbo.life/api/brands \
  -H "Authorization: Bearer eyJhbGc..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "WE ARE HYBRID. IN",
    "domain": "wearehybrid.in",
    "owner_email": "admin@legacy-integration.cloud",
    "settings": {
      "timezone": "Asia/Kolkata",
      "currency": "INR"
    }
  }'

# Response:
{
  "success": true,
  "brand": {
    "id": "brand_abc123",
    "name": "WE ARE HYBRID. IN",
    "domain": "wearehybrid.in"
  }
}

Step 3: Generate API Key

# 3. Generate API key
curl -X POST https://jinbo.life/api/auth/api-key \
  -H "Authorization: Bearer eyJhbGc..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "WE ARE HYBRID Production",
    "scopes": ["*"]
  }'

# Response:
{
  "api_key": "jinbo_live_1234567890abcdef",
  "brand_id": "brand_abc123",
  "scopes": ["*"],
  "created_at": "2025-10-02T02:00:00Z"
}

# ⚠️ SAVE THIS! You'll never see it again.

Step 4: Create Classes via API

# 4. Create yoga class
curl -X POST https://jinbo.life/api/classes \
  -H "X-API-Key: jinbo_live_1234567890abcdef" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Morning Yoga Flow",
    "description": "Energizing vinyasa flow for all levels",
    "skill_id": "skill_yoga",
    "level": "beginner",
    "max_students": 15,
    "duration_minutes": 60,
    "schedule": {
      "days": ["monday", "wednesday", "friday"],
      "time": "07:00",
      "timezone": "Asia/Kolkata"
    },
    "pricing": {
      "amount": 5000,
      "currency": "INR",
      "billing_cycle": "monthly"
    }
  }'

# Response:
{
  "success": true,
  "class": {
    "id": "class_xyz789",
    "name": "Morning Yoga Flow",
    "max_students": 15,
    "enrolled_students": 0,
    "coach_id": null,
    "status": "active"
  }
}

Step 5: Invite Coach

# 5. Invite coach
curl -X POST https://jinbo.life/api/users/invite \
  -H "X-API-Key: jinbo_live_1234567890abcdef" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "priya@wearehybrid.in",
    "name": "Priya Sharma",
    "role": "coach",
    "skills": ["yoga", "pilates"]
  }'

# Response:
{
  "success": true,
  "user": {
    "id": "user_coach1",
    "email": "priya@wearehybrid.in",
    "name": "Priya Sharma",
    "role": "coach"
  }
}

Step 6: Assign Coach to Class

# 6. Assign coach
curl -X POST https://jinbo.life/api/classes/class_xyz789/assign-coach \
  -H "X-API-Key: jinbo_live_1234567890abcdef" \
  -H "Content-Type: application/json" \
  -d '{
    "coach_id": "user_coach1"
  }'

# Response:
{
  "success": true,
  "class": {
    "id": "class_xyz789",
    "name": "Morning Yoga Flow",
    "coach": {
      "id": "user_coach1",
      "name": "Priya Sharma",
      "email": "priya@wearehybrid.in"
    }
  },
  "assigned_at": "2025-10-02T02:00:00Z"
}

🛡️ SECURITY FEATURES

1. Key Hashing

// We NEVER store plain text keys
const apiKey = 'jinbo_live_1234567890abcdef';
const keyHash = crypto.createHash('sha256').update(apiKey).digest('hex');
// Store keyHash in database, not apiKey!

2. Brand Isolation

-- Every query is scoped to brand
SELECT * FROM classes WHERE brand_id = $1;

-- RLS (Row Level Security) enforces this at database level
CREATE POLICY classes_brand_isolation ON classes
  USING (brand_id = current_setting('app.brand_id')::UUID);

3. Scope Checking

// API keys can only do what they're allowed
if (!scopes.includes('*') && !scopes.includes('classes:write')) {
  return res.status(403).json({ error: 'Insufficient permissions' });
}

4. Audit Logging

-- Every API key usage is logged
INSERT INTO api_key_logs (
  api_key_id, endpoint, method, status_code, ip_address
) VALUES ($1, $2, $3, $4, $5);

5. Revocation

// Instantly disable compromised keys
UPDATE api_keys 
SET revoked_at = NOW() 
WHERE id = 'compromised_key_id';

📊 API KEY MANAGEMENT

List All Keys

GET https://jinbo.life/api/auth/api-keys
Headers: { "Authorization": "Bearer JWT_TOKEN" }

Response:
{
  "keys": [
    {
      "id": "key1",
      "name": "Production Key",
      "scopes": ["*"],
      "created_at": "2025-10-01",
      "last_used_at": "2025-10-02T01:30:00Z"
    },
    {
      "id": "key2",
      "name": "Read-Only Key",
      "scopes": ["classes:read", "students:read"],
      "created_at": "2025-10-01",
      "last_used_at": "2025-10-02T00:15:00Z"
    }
  ]
}

Revoke Key

DELETE https://jinbo.life/api/auth/api-keys/key1
Headers: { "Authorization": "Bearer JWT_TOKEN" }

Response:
{
  "success": true,
  "message": "API key revoked successfully"
}

View Usage Stats

GET https://jinbo.life/api/auth/api-keys/key1/stats
Headers: { "Authorization": "Bearer JWT_TOKEN" }

Response:
{
  "total_requests": 1543,
  "last_30_days": 892,
  "endpoints": {
    "/api/classes": 650,
    "/api/students": 320,
    "/api/sessions": 122
  },
  "last_used": "2025-10-02T01:30:00Z"
}

🎯 SUMMARY FOR WE ARE HYBRID. IN

What You Get:

  1. Your own brand in JINBO system
  2. API key for automation (jinbo_live_...)
  3. Full API access to:
    • Create/manage classes
    • Invite/assign coaches
    • Enroll students
    • Track progress
    • Access analytics

How to Use It:

// Simple! Just add X-API-Key header
const response = await fetch('https://jinbo.life/api/classes', {
  method: 'POST',
  headers: {
    'X-API-Key': 'jinbo_live_YOUR_KEY_HERE',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'New Class',
    skill_id: 'yoga',
    level: 'beginner'
  })
});

Security:

Support:


Ready to integrate! 🚀

Last Updated: October 2, 2025 - 02:10 UTC