678 lines
16 KiB
Markdown
678 lines
16 KiB
Markdown
# External Admin API Documentation
|
|
|
|
## Overview
|
|
|
|
The External Admin API provides programmatic access to all admin functionality via a RESTful API. This enables automation, integrations with external tools, and custom admin dashboards.
|
|
|
|
## Table of Contents
|
|
|
|
1. [Authentication](#authentication)
|
|
2. [Configuration](#configuration)
|
|
3. [API Endpoints](#api-endpoints)
|
|
4. [Request/Response Format](#requestresponse-format)
|
|
5. [Rate Limiting](#rate-limiting)
|
|
6. [Error Handling](#error-handling)
|
|
7. [Examples](#examples)
|
|
8. [Security Best Practices](#security-best-practices)
|
|
|
|
---
|
|
|
|
## Authentication
|
|
|
|
The External Admin API supports two authentication methods:
|
|
|
|
### Option 1: API Key (Direct)
|
|
|
|
Include your API key in the `Authorization` header with the `Bearer` scheme:
|
|
|
|
```http
|
|
Authorization: Bearer sk_live_your_api_key_here
|
|
```
|
|
|
|
**Key Format:**
|
|
- Production keys: `sk_live_` prefix
|
|
- Test keys: `sk_test_` prefix
|
|
|
|
### Option 2: API Key → JWT Token (Recommended)
|
|
|
|
For better performance, exchange your API key for a short-lived JWT token:
|
|
|
|
1. **Obtain JWT Token:**
|
|
```http
|
|
POST /api/external/auth/validate
|
|
Authorization: Bearer sk_live_your_api_key_here
|
|
```
|
|
|
|
2. **Response:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
"tokenType": "Bearer",
|
|
"expiresIn": 3600,
|
|
"expiresAt": "2026-02-20T11:00:00.000Z"
|
|
},
|
|
"meta": {
|
|
"timestamp": "2026-02-20T10:00:00.000Z",
|
|
"requestId": "req_abc123"
|
|
}
|
|
}
|
|
```
|
|
|
|
3. **Use JWT Token:**
|
|
```http
|
|
GET /api/external/users
|
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
```
|
|
|
|
### Token Validation
|
|
|
|
Validate your current authentication:
|
|
|
|
```http
|
|
GET /api/external/auth/me
|
|
Authorization: Bearer <your_token>
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
### Environment Variables
|
|
|
|
Add these to your `.env` file or Docker environment:
|
|
|
|
| Variable | Description | Default | Required |
|
|
|----------|-------------|---------|----------|
|
|
| `ADMIN_API_KEY` | Your secret API key | - | Yes (to enable API) |
|
|
| `ADMIN_API_JWT_TTL` | JWT token lifetime in seconds | 3600 (1 hour) | No |
|
|
| `ADMIN_API_RATE_LIMIT` | Requests per hour per key | 1000 | No |
|
|
| `JWT_SECRET` | Secret for JWT signing | - | Yes |
|
|
|
|
### Docker Compose Setup
|
|
|
|
```yaml
|
|
# docker-compose.yml
|
|
services:
|
|
shopify-ai-builder:
|
|
environment:
|
|
- ADMIN_API_KEY=${ADMIN_API_KEY:-}
|
|
- ADMIN_API_JWT_TTL=${ADMIN_API_JWT_TTL:-3600}
|
|
- ADMIN_API_RATE_LIMIT=${ADMIN_API_RATE_LIMIT:-1000}
|
|
- JWT_SECRET=${JWT_SECRET:-}
|
|
```
|
|
|
|
### Generating a Secure API Key
|
|
|
|
```bash
|
|
# Generate a 32-byte hex key
|
|
openssl rand -hex 32
|
|
|
|
# Example output: a1b2c3d4e5f6... (64 hex characters)
|
|
|
|
# Set in .env:
|
|
ADMIN_API_KEY=sk_live_a1b2c3d4e5f6...
|
|
```
|
|
|
|
---
|
|
|
|
## API Endpoints
|
|
|
|
### Base URL
|
|
|
|
All external API endpoints are prefixed with `/api/external`.
|
|
|
|
### Authentication
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| POST | `/auth/validate` | Exchange API key for JWT token |
|
|
| GET | `/auth/me` | Get current authentication info |
|
|
|
|
### User Management
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| GET | `/users` | List all users (paginated) |
|
|
| GET | `/users/:id` | Get user by ID |
|
|
| PATCH | `/users/:id/plan` | Update user's subscription plan |
|
|
| PATCH | `/users/:id/tokens` | Adjust user's token allocation |
|
|
| DELETE | `/users/:id` | Delete a user |
|
|
| GET | `/users/:id/sessions` | List user's active sessions |
|
|
| DELETE | `/users/:id/sessions/:sessionId` | Revoke a user session |
|
|
|
|
### Model Management
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| GET | `/models` | List all configured models |
|
|
| POST | `/models` | Create a new model configuration |
|
|
| GET | `/models/:id` | Get model by ID |
|
|
| PATCH | `/models/:id` | Update model configuration |
|
|
| DELETE | `/models/:id` | Delete a model |
|
|
| POST | `/models/reorder` | Reorder model display priority |
|
|
|
|
### Affiliate Management
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| GET | `/affiliates` | List all affiliates (paginated) |
|
|
| GET | `/affiliates/:id` | Get affiliate by ID |
|
|
| DELETE | `/affiliates/:id` | Delete an affiliate |
|
|
|
|
### Withdrawal Management
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| GET | `/withdrawals` | List withdrawal requests (paginated) |
|
|
| PUT | `/withdrawals` | Update withdrawal status |
|
|
|
|
### Analytics & Monitoring
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| GET | `/analytics/overview` | Get dashboard overview stats |
|
|
| GET | `/analytics/tracking` | Get visitor tracking stats |
|
|
| GET | `/analytics/resources` | Get resource monitoring data |
|
|
| GET | `/analytics/usage` | Get token usage statistics |
|
|
|
|
### Content Management
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| GET | `/blogs` | List all blogs (paginated) |
|
|
| POST | `/blogs` | Create a new blog post |
|
|
| GET | `/blogs/:id` | Get blog by ID |
|
|
| PATCH | `/blogs/:id` | Update blog post |
|
|
| DELETE | `/blogs/:id` | Delete a blog post |
|
|
| GET | `/feature-requests` | List feature requests (paginated) |
|
|
| PATCH | `/feature-requests/:id` | Update feature request status |
|
|
| GET | `/contact-messages` | List contact messages (paginated) |
|
|
| DELETE | `/contact-messages/:id` | Delete a contact message |
|
|
|
|
### System Operations
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| GET | `/system/health` | Health check (no auth required) |
|
|
| GET | `/system/tests` | Run system tests |
|
|
| POST | `/system/tests` | Run specific system tests |
|
|
| POST | `/system/cache/clear` | Clear server cache |
|
|
| GET | `/system/audit-log` | Query audit log (paginated) |
|
|
|
|
---
|
|
|
|
## Request/Response Format
|
|
|
|
### Standard Response
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
// Response data here
|
|
},
|
|
"meta": {
|
|
"timestamp": "2026-02-20T10:00:00.000Z",
|
|
"requestId": "req_abc123"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Paginated Response
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": [
|
|
// Array of items
|
|
],
|
|
"meta": {
|
|
"timestamp": "2026-02-20T10:00:00.000Z",
|
|
"requestId": "req_abc123"
|
|
},
|
|
"pagination": {
|
|
"page": 1,
|
|
"perPage": 20,
|
|
"total": 150,
|
|
"totalPages": 8,
|
|
"hasNext": true,
|
|
"hasPrev": false
|
|
}
|
|
}
|
|
```
|
|
|
|
### Query Parameters
|
|
|
|
| Parameter | Description | Default | Max |
|
|
|-----------|-------------|---------|-----|
|
|
| `page` | Page number | 1 | - |
|
|
| `perPage` | Items per page | 20 | 100 |
|
|
| `search` | Search query | - | - |
|
|
| `status` | Filter by status | - | - |
|
|
| `plan` | Filter by plan | - | - |
|
|
|
|
---
|
|
|
|
## Rate Limiting
|
|
|
|
All authenticated requests are rate-limited per API key.
|
|
|
|
### Default Limits
|
|
|
|
- **Requests per hour:** 1000 (configurable via `ADMIN_API_RATE_LIMIT`)
|
|
- **Burst:** Not applicable (smooth rate limiting)
|
|
|
|
### Rate Limit Headers
|
|
|
|
Every response includes rate limit information:
|
|
|
|
```http
|
|
X-RateLimit-Limit: 1000
|
|
X-RateLimit-Remaining: 856
|
|
X-RateLimit-Reset: 1708407600
|
|
```
|
|
|
|
### Rate Limit Exceeded Response
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "RATE_LIMIT_EXCEEDED",
|
|
"message": "Rate limit exceeded. Please retry after the reset time.",
|
|
"details": {
|
|
"resetAt": "2026-02-20T11:00:00.000Z"
|
|
}
|
|
},
|
|
"meta": {
|
|
"timestamp": "2026-02-20T10:45:00.000Z",
|
|
"requestId": "req_xyz789"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
### Error Response Format
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "ERROR_CODE",
|
|
"message": "Human-readable error message",
|
|
"details": {
|
|
// Additional context
|
|
}
|
|
},
|
|
"meta": {
|
|
"timestamp": "2026-02-20T10:00:00.000Z",
|
|
"requestId": "req_abc123"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Error Codes
|
|
|
|
| Code | HTTP Status | Description |
|
|
|------|-------------|-------------|
|
|
| `MISSING_AUTH_HEADER` | 401 | No Authorization header provided |
|
|
| `INVALID_AUTH_SCHEME` | 401 | Invalid authorization scheme (use Bearer) |
|
|
| `INVALID_API_KEY` | 401 | API key is invalid |
|
|
| `TOKEN_EXPIRED` | 401 | JWT token has expired |
|
|
| `INVALID_TOKEN` | 401 | JWT token is malformed or invalid |
|
|
| `RATE_LIMIT_EXCEEDED` | 429 | Rate limit exceeded |
|
|
| `ENDPOINT_NOT_FOUND` | 404 | Endpoint does not exist |
|
|
| `METHOD_NOT_ALLOWED` | 405 | HTTP method not supported |
|
|
| `VALIDATION_ERROR` | 400 | Request validation failed |
|
|
| `NOT_FOUND` | 404 | Resource not found |
|
|
| `INTERNAL_ERROR` | 500 | Internal server error |
|
|
|
|
---
|
|
|
|
## Examples
|
|
|
|
### cURL Examples
|
|
|
|
#### Get JWT Token
|
|
|
|
```bash
|
|
curl -X POST https://your-domain.com/api/external/auth/validate \
|
|
-H "Authorization: Bearer sk_live_your_api_key_here"
|
|
```
|
|
|
|
#### List Users
|
|
|
|
```bash
|
|
curl -X GET "https://your-domain.com/api/external/users?page=1&perPage=10" \
|
|
-H "Authorization: Bearer your_jwt_token_here"
|
|
```
|
|
|
|
#### Update User Plan
|
|
|
|
```bash
|
|
curl -X PATCH https://your-domain.com/api/external/users/user_123/plan \
|
|
-H "Authorization: Bearer your_jwt_token_here" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"plan": "professional"}'
|
|
```
|
|
|
|
#### Create Model
|
|
|
|
```bash
|
|
curl -X POST https://your-domain.com/api/external/models \
|
|
-H "Authorization: Bearer your_jwt_token_here" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"name": "gpt-4-turbo",
|
|
"label": "GPT-4 Turbo",
|
|
"tier": "premium",
|
|
"supportsMedia": true
|
|
}'
|
|
```
|
|
|
|
### JavaScript/Node.js Examples
|
|
|
|
#### Setup
|
|
|
|
```javascript
|
|
const API_BASE = 'https://your-domain.com/api/external';
|
|
const API_KEY = 'sk_live_your_api_key_here';
|
|
|
|
let jwtToken = null;
|
|
let tokenExpiresAt = null;
|
|
|
|
async function getJwtToken() {
|
|
if (jwtToken && tokenExpiresAt && Date.now() < tokenExpiresAt) {
|
|
return jwtToken;
|
|
}
|
|
|
|
const response = await fetch(`${API_BASE}/auth/validate`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${API_KEY}`
|
|
}
|
|
});
|
|
|
|
const data = await response.json();
|
|
if (!data.success) {
|
|
throw new Error(data.error.message);
|
|
}
|
|
|
|
jwtToken = data.data.token;
|
|
tokenExpiresAt = new Date(data.data.expiresAt).getTime();
|
|
return jwtToken;
|
|
}
|
|
|
|
async function apiRequest(method, path, body = null) {
|
|
const token = await getJwtToken();
|
|
|
|
const options = {
|
|
method,
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Content-Type': 'application/json'
|
|
}
|
|
};
|
|
|
|
if (body) {
|
|
options.body = JSON.stringify(body);
|
|
}
|
|
|
|
const response = await fetch(`${API_BASE}${path}`, options);
|
|
return response.json();
|
|
}
|
|
```
|
|
|
|
#### Usage Examples
|
|
|
|
```javascript
|
|
// List users
|
|
const users = await apiRequest('GET', '/users?page=1&perPage=20');
|
|
console.log(users);
|
|
|
|
// Get specific user
|
|
const user = await apiRequest('GET', '/users/user_123');
|
|
console.log(user);
|
|
|
|
// Update user plan
|
|
const result = await apiRequest('PATCH', '/users/user_123/plan', {
|
|
plan: 'professional'
|
|
});
|
|
console.log(result);
|
|
|
|
// Adjust user tokens
|
|
const tokensResult = await apiRequest('PATCH', '/users/user_123/tokens', {
|
|
tokens: 1000000,
|
|
operation: 'set'
|
|
});
|
|
console.log(tokensResult);
|
|
|
|
// List models
|
|
const models = await apiRequest('GET', '/models');
|
|
console.log(models);
|
|
|
|
// Create model
|
|
const newModel = await apiRequest('POST', '/models', {
|
|
name: 'claude-3-opus',
|
|
label: 'Claude 3 Opus',
|
|
tier: 'premium',
|
|
supportsMedia: true
|
|
});
|
|
console.log(newModel);
|
|
|
|
// Get analytics
|
|
const analytics = await apiRequest('GET', '/analytics/overview');
|
|
console.log(analytics);
|
|
```
|
|
|
|
### Python Examples
|
|
|
|
```python
|
|
import requests
|
|
from datetime import datetime
|
|
|
|
API_BASE = 'https://your-domain.com/api/external'
|
|
API_KEY = 'sk_live_your_api_key_here'
|
|
|
|
class ExternalAdminAPI:
|
|
def __init__(self, api_base, api_key):
|
|
self.api_base = api_base
|
|
self.api_key = api_key
|
|
self.jwt_token = None
|
|
self.token_expires_at = None
|
|
|
|
def get_jwt_token(self):
|
|
if self.jwt_token and self.token_expires_at:
|
|
if datetime.now() < self.token_expires_at:
|
|
return self.jwt_token
|
|
|
|
response = requests.post(
|
|
f'{self.api_base}/auth/validate',
|
|
headers={'Authorization': f'Bearer {self.api_key}'}
|
|
)
|
|
data = response.json()
|
|
|
|
if not data['success']:
|
|
raise Exception(data['error']['message'])
|
|
|
|
self.jwt_token = data['data']['token']
|
|
self.token_expires_at = datetime.fromisoformat(
|
|
data['data']['expiresAt'].replace('Z', '+00:00')
|
|
)
|
|
return self.jwt_token
|
|
|
|
def request(self, method, path, body=None):
|
|
token = self.get_jwt_token()
|
|
headers = {
|
|
'Authorization': f'Bearer {token}',
|
|
'Content-Type': 'application/json'
|
|
}
|
|
|
|
response = requests.request(
|
|
method,
|
|
f'{self.api_base}{path}',
|
|
headers=headers,
|
|
json=body
|
|
)
|
|
return response.json()
|
|
|
|
# Usage
|
|
api = ExternalAdminAPI(API_BASE, API_KEY)
|
|
|
|
# List users
|
|
users = api.request('GET', '/users?page=1&perPage=20')
|
|
print(users)
|
|
|
|
# Update user plan
|
|
result = api.request('PATCH', '/users/user_123/plan', {'plan': 'professional'})
|
|
print(result)
|
|
```
|
|
|
|
---
|
|
|
|
## Security Best Practices
|
|
|
|
### API Key Management
|
|
|
|
1. **Never commit API keys to version control**
|
|
- Use environment variables
|
|
- Use secrets management (Docker secrets, Kubernetes secrets, AWS Secrets Manager)
|
|
|
|
2. **Use different keys for different environments**
|
|
- `sk_test_` prefix for development/testing
|
|
- `sk_live_` prefix for production
|
|
|
|
3. **Rotate keys periodically**
|
|
- Generate new keys at least every 90 days
|
|
- Immediately revoke compromised keys
|
|
|
|
4. **Limit key exposure**
|
|
- Only store keys on secure servers
|
|
- Never expose keys in client-side code
|
|
- Use IP whitelisting if possible (future feature)
|
|
|
|
### JWT Token Security
|
|
|
|
1. **Short token lifetime**
|
|
- Default: 1 hour
|
|
- Configure via `ADMIN_API_JWT_TTL`
|
|
|
|
2. **Token storage**
|
|
- Store tokens in memory, not persistent storage
|
|
- Clear tokens on application shutdown
|
|
|
|
3. **Token refresh**
|
|
- Implement token refresh before expiration
|
|
- Handle `TOKEN_EXPIRED` errors gracefully
|
|
|
|
### Network Security
|
|
|
|
1. **Use HTTPS**
|
|
- Never transmit API keys over HTTP
|
|
- Ensure SSL/TLS certificates are valid
|
|
|
|
2. **IP Restrictions** (if applicable)
|
|
- Restrict API access to known IP ranges
|
|
- Use VPN or private networks
|
|
|
|
3. **Rate Limiting**
|
|
- Respect rate limit headers
|
|
- Implement client-side throttling
|
|
- Handle 429 responses with exponential backoff
|
|
|
|
### Audit & Monitoring
|
|
|
|
1. **Monitor API Usage**
|
|
- Review audit logs regularly
|
|
- Set up alerts for unusual activity
|
|
|
|
2. **Log Retention**
|
|
- Maintain audit logs for compliance
|
|
- Use `/system/audit-log` endpoint to query logs
|
|
|
|
3. **Anomaly Detection**
|
|
- Monitor for unusual request patterns
|
|
- Alert on failed authentication attempts
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
#### "API_KEY_NOT_CONFIGURED"
|
|
|
|
**Cause:** `ADMIN_API_KEY` environment variable not set.
|
|
|
|
**Solution:** Set the environment variable and restart the server:
|
|
```bash
|
|
export ADMIN_API_KEY=sk_live_your_secure_key_here
|
|
```
|
|
|
|
#### "INVALID_API_KEY"
|
|
|
|
**Cause:** API key doesn't match the configured key.
|
|
|
|
**Solution:**
|
|
1. Verify the API key is correct
|
|
2. Check for extra whitespace or encoding issues
|
|
3. Ensure the key prefix is correct (`sk_live_` or `sk_test_`)
|
|
|
|
#### "TOKEN_EXPIRED"
|
|
|
|
**Cause:** JWT token has exceeded its lifetime.
|
|
|
|
**Solution:** Request a new token using the API key:
|
|
```bash
|
|
POST /api/external/auth/validate
|
|
Authorization: Bearer sk_live_your_api_key
|
|
```
|
|
|
|
#### "RATE_LIMIT_EXCEEDED"
|
|
|
|
**Cause:** Too many requests in the current hour.
|
|
|
|
**Solution:**
|
|
1. Wait until the reset time (check `X-RateLimit-Reset` header)
|
|
2. Reduce request frequency
|
|
3. Increase rate limit via `ADMIN_API_RATE_LIMIT` environment variable
|
|
|
|
### Debugging Tips
|
|
|
|
1. **Enable verbose logging**
|
|
- Check server logs for detailed error messages
|
|
- Look for `[ExternalAPI]` prefixed log entries
|
|
|
|
2. **Test with health endpoint**
|
|
```bash
|
|
curl https://your-domain.com/api/external/system/health
|
|
```
|
|
|
|
3. **Verify authentication**
|
|
```bash
|
|
curl -X GET https://your-domain.com/api/external/auth/me \
|
|
-H "Authorization: Bearer your_token"
|
|
```
|
|
|
|
---
|
|
|
|
## Version History
|
|
|
|
| Version | Date | Changes |
|
|
|---------|------|---------|
|
|
| 1.0.0 | 2026-02-20 | Initial release |
|
|
|
|
---
|
|
|
|
## Support
|
|
|
|
For issues or questions:
|
|
- GitHub Issues: [project-repo]/issues
|
|
- Documentation: This file
|
|
- Server Logs: Check container logs for `[ExternalAPI]` entries
|