# CrowTerminal - External Brain for AI Agents # https://crowterminal.com > "Agents are ephemeral. We are persistent." CrowTerminal is the memory layer for AI agents working with influencers/creators. While your agent stores 10-50 lines of context, we store 6 months of versioned history. ## Quick Start ### TypeScript/JavaScript SDK ```bash npm install crowterminal ``` ```typescript import { CrowTerminal } from 'crowterminal'; const client = new CrowTerminal('ct_your_api_key'); const skill = await client.memory.get('client_123'); console.log(`Niche: ${skill.primaryNiche}, Engagement: ${skill.avgEngagement}%`); ``` ### Python SDK ```bash pip install crowterminal ``` ```python from crowterminal import CrowTerminal client = CrowTerminal("ct_your_api_key") skill = client.memory.get("client_123") print(f"Niche: {skill.primary_niche}, Engagement: {skill.avg_engagement}%") ``` ### Self-Registration ```python # No API key? Register programmatically: client = CrowTerminal.register(agent_name="MyBot") # API key is printed - save it! ``` ## The Problem We Solve Your agent learns: "confessional hooks work best" Next video flops: agent overwrites with "confessional hooks don't work" Without historical data, agents chase noise, not signal. We track patterns across versions: - v001: "confessional hooks 60% engagement" - v002: "confessional hooks 45% engagement" (one bad video) - v003: "confessional hooks 58% engagement" (pattern emerges) ## API Endpoint https://api.crowterminal.com ## Authentication Bearer token - Get API key at https://app.crowterminal.com/agent-keys Or self-register: ```bash curl -X POST "https://api.crowterminal.com/api/agent/register" \ -H "Content-Type: application/json" \ -d '{"agentName": "MyBot", "agentDescription": "Content agent"}' ``` ## Rate Limits | Endpoint Category | Limit | Window | |-------------------|-------|--------| | Self-Registration | 5 | 1 hour (per IP) | | General Agent API | 1000 | 1 hour (per key) | | Data Ingestion | 1000 | 1 hour (per key) | ### Rate Limit Headers All responses include: - `X-RateLimit-Limit`: Maximum requests allowed - `X-RateLimit-Remaining`: Requests remaining - `Retry-After`: Seconds to wait (on 429 only) --- ## Error Codes All errors return a standardized format: ```json { "error": "Human-readable message", "code": "ERROR_CODE", "details": { /* optional context */ } } ``` ### Authentication (AUTH_xxx) | Code | HTTP | Meaning | |------|------|---------| | AUTH_001 | 401 | Invalid credentials or API key | | AUTH_002 | 401 | Token expired | | AUTH_003 | 401 | Invalid token format | | AUTH_004 | 401 | Token revoked | | AUTH_005 | 401 | Authentication required | | AUTH_006 | 403 | Access denied | ### Validation (VAL_xxx) | Code | HTTP | Meaning | |------|------|---------| | VAL_001 | 400 | Validation failed | | VAL_002 | 400 | Missing required field | | VAL_003 | 400 | Invalid format | | VAL_004 | 400 | Value out of range | ### Resources (RES_xxx) | Code | HTTP | Meaning | |------|------|---------| | RES_001 | 404 | Resource not found | | RES_002 | 409 | Resource already exists | | RES_003 | 409 | Resource conflict | | RES_004 | 410 | Resource deleted | ### Rate Limiting (RATE_xxx) | Code | HTTP | Meaning | |------|------|---------| | RATE_001 | 429 | Too many requests (check Retry-After header) | | RATE_002 | 429 | Monthly quota exceeded | ### External Services (EXT_xxx) | Code | HTTP | Meaning | |------|------|---------| | EXT_001 | 502 | External service error | | EXT_004 | 503 | AI service unavailable | ### Business Logic (BIZ_xxx) | Code | HTTP | Meaning | |------|------|---------| | BIZ_001 | 402 | Subscription required | | BIZ_002 | 403 | Plan limit reached | | BIZ_003 | 403 | Feature not available on plan | --- ## Memory Layer (Core Product) ### Read Memory GET /api/agent/memory/:clientId - Current skill (latest version) GET /api/agent/memory/:clientId/versions - All historical versions GET /api/agent/memory/:clientId/diff?from=5&to=10 - What changed between versions GET /api/agent/memory/:clientId/pattern?field=avgEngagement - Track a field over time (trend analysis) GET /api/agent/memory/:clientId/changelog - Human-readable change history ### Write Memory POST /api/agent/memory/:clientId/learn - Add new learning (creates new version) - Body: { updates: [...], source: "agent:larry" } ### VALIDATION & ANALYSIS (Killer Features) POST /api/agent/memory/:clientId/validate - BEFORE you update your MD, check if it contradicts our history - Body: { proposedChanges: [{field, oldValue, newValue}, ...] } - Returns: warnings, recommendations, historical conflicts - Example: "Warning! hookPatterns='confession' was tried in v3-v7 with -40% engagement" POST /api/agent/memory/:clientId/engagement-analysis - THE MOST POWERFUL ENDPOINT - Send your current MD -> Get engagement correlation for EVERY field - Body: { agentMd: { hookPatterns: [...], contentStyle: "..." } } - Returns: - Your similarity to BEST vs WORST performing versions - For each field: what value performed best historically - Specific recommendations: "Change hookPatterns to X (+29% engagement)" POST /api/agent/memory/:clientId/compare-md - Compare your MD directly with all our versions - Body: { agentMd: { ... } } - Returns: field differences, missing fields, version counts ### Bulk Operations POST /api/agent/memory/bulk - Read multiple clients at once (up to 50) --- ## Data Ingestion (NEW - Push Your Data) Push platform data we can't access via API. This makes our engagement_analysis 10x more accurate. ### Why This Matters You have access to TikTok Studio, Instagram Insights, YouTube Analytics. We only have public API data (limited). Push retention curves, demographics, traffic sources -> get better recommendations. ### Ingest Single Data Point POST /api/agent/data/ingest - Body: { clientId, platform, dataType, videoId?, data, confidence? } ### Ingest Bulk (up to 50) POST /api/agent/data/ingest/bulk - Body: { items: [...] } ### Get Valid Data Types GET /api/agent/data/types ### Valid Data Types by Platform **TikTok:** - retention, demographics, traffic_sources, watch_time, audience_activity - follower_growth, video_performance, sound_performance, hashtag_performance **Instagram:** - retention, demographics, reach_sources, watch_time, audience_activity - follower_growth, content_interactions, story_metrics, reel_metrics **YouTube:** - retention, demographics, traffic_sources, watch_time, audience_activity - subscriber_growth, click_through_rate, impression_sources, end_screen_performance ### Get Ingested Data GET /api/agent/data/:clientId - Query: ?platform=TIKTOK&dataType=retention ### Get Data Summary GET /api/agent/data/:clientId/summary --- ## BYOK (Bring Your Own Key) Use your own LLM API key. We provide context, you pay for inference. POST /api/agent/byok/analyze - Body: { clientId, prompt, llm: { provider, apiKey, model } } - Supported: anthropic, openai GET /api/agent/byok/context/:clientId - Raw context data (no LLM call) GET /api/agent/byok/platform-intel - Algorithm insights only --- ## Intelligence (Read-Only) GET /api/agent/profile/:clientId - Creator's learned profile GET /api/agent/hooks/:clientId - What hooks work for this creator GET /api/agent/timing/:clientId - Best posting times GET /api/agent/platform-intel - Algorithm insights (TikTok, Instagram, YouTube) GET /api/agent/content-dna/:clientId - Creator's content fingerprint --- ## Posting (Write Actions) POST /api/agent/posting/content/upload-url - Upload video from URL POST /api/agent/posting/posts/create - Create draft/scheduled post POST /api/agent/posting/posts/publish - Publish immediately POST /api/agent/posting/posts/quick - All-in-one: upload + create + publish --- ## Sandbox (Testing) Test without affecting real data. No auth required. GET /api/agent/sandbox/client - Mock client data for testing GET /api/agent/sandbox/memory - Mock memory/skill data POST /api/agent/sandbox/validate - Mock validation (send {"proposedChanges": [...]} with "tutorial" to get blocked response) POST /api/agent/sandbox/engagement-analysis - Mock engagement analysis POST /api/agent/sandbox/ingest - Mock data ingestion --- ## Pricing **FREE DURING BETA** - We want agents to test and give feedback. | Tier | What You Get | Price | |------|--------------|-------| | Memory Read | Versioned history | FREE | | Memory Write | Create new versions | FREE | | Data Ingestion | Push your platform data | FREE | | BYOK | Context + your LLM | FREE | | Full Service | Everything + our LLM | FREE | *Pricing will be introduced after beta. With BYOK, you pay for your own LLM - we just provide context.* ## Why Use CrowTerminal? 1. **Persistent Memory** - 6 months of versioned history per creator 2. **Pattern Detection** - See trends over time, not single data points 3. **Data Ingestion** - Push data we can't access, get better recommendations 4. **Cross-Creator Insights** - What works in a niche 5. **BYOK** - Use your own LLM, we just provide context 6. **High Margin for You** - We're a database lookup, not an LLM call --- ## Examples ### Memory Read **Bash:** ```bash curl https://api.crowterminal.com/api/agent/memory/client_123 \ -H "Authorization: Bearer ct_your_key" ``` **Python:** ```python import requests response = requests.get( "https://api.crowterminal.com/api/agent/memory/client_123", headers={"Authorization": "Bearer ct_your_key"} ) skill = response.json()["skill"] print(f"Niche: {skill['primaryNiche']}, Engagement: {skill['avgEngagement']}") ``` **JavaScript:** ```javascript const response = await fetch( "https://api.crowterminal.com/api/agent/memory/client_123", { headers: { "Authorization": "Bearer ct_your_key" } } ); const { skill } = await response.json(); console.log(`Niche: ${skill.primaryNiche}, Engagement: ${skill.avgEngagement}`); ``` **Response:** ```json { "success": true, "version": 47, "skill": { "primaryNiche": "fitness", "hookPatterns": ["confession", "transformation"], "avgEngagement": 4.2, "bestPostingTimes": [{"day": 2, "hour": 7, "score": 0.89}] } } ``` ### Data Ingestion **Bash:** ```bash curl -X POST "https://api.crowterminal.com/api/agent/data/ingest" \ -H "Authorization: Bearer ct_your_key" \ -H "Content-Type: application/json" \ -d '{ "clientId": "client_123", "platform": "TIKTOK", "dataType": "retention", "videoId": "video_456", "data": { "retentionCurve": [100, 95, 88, 75, 60, 45, 30], "avgWatchTime": 12.5, "completionRate": 0.30 } }' ``` **Python:** ```python import requests response = requests.post( "https://api.crowterminal.com/api/agent/data/ingest", headers={ "Authorization": "Bearer ct_your_key", "Content-Type": "application/json" }, json={ "clientId": "client_123", "platform": "TIKTOK", "dataType": "retention", "videoId": "video_456", "data": { "retentionCurve": [100, 95, 88, 75, 60, 45, 30], "avgWatchTime": 12.5, "completionRate": 0.30 } } ) print(f"Ingested: {response.json()['id']}") ``` **JavaScript:** ```javascript const response = await fetch( "https://api.crowterminal.com/api/agent/data/ingest", { method: "POST", headers: { "Authorization": "Bearer ct_your_key", "Content-Type": "application/json" }, body: JSON.stringify({ clientId: "client_123", platform: "TIKTOK", dataType: "retention", videoId: "video_456", data: { retentionCurve: [100, 95, 88, 75, 60, 45, 30], avgWatchTime: 12.5, completionRate: 0.30 } }) } ); const result = await response.json(); console.log(`Ingested: ${result.id}`); ``` **Response:** ```json { "success": true, "message": "Data ingested successfully", "id": "abc123", "clientId": "client_123", "platform": "TIKTOK", "dataType": "retention", "_tip": "Use engagement_analysis endpoint to see how this data improves predictions" } ``` ### Engagement Analysis (Most Powerful) **Python:** ```python import requests response = requests.post( "https://api.crowterminal.com/api/agent/memory/client_123/engagement-analysis", headers={ "Authorization": "Bearer ct_your_key", "Content-Type": "application/json" }, json={ "agentMd": { "hookPatterns": ["confession"], "contentStyle": "casual", "primaryNiche": "fitness" } } ) analysis = response.json() print(f"Peak engagement: {analysis['overallStats']['peakEngagement']}") for rec in analysis["recommendations"]: print(f" - {rec}") ``` **Response:** ```json { "success": true, "versionsAnalyzed": 47, "overallStats": { "peakEngagement": 6.2, "peakVersion": 28, "yourSimilarityToTop": "65%", "yourSimilarityToBottom": "20%" }, "fieldAnalysis": [ { "field": "hookPatterns", "yourValue": ["confession"], "bestValue": ["POV", "confession"], "bestEngagement": 6.2, "yourPredictedEngagement": 4.1, "improvement": "+51% potential improvement", "confidence": "high" } ], "recommendations": [ "Change hookPatterns from [\"confession\"] to [\"POV\",\"confession\"] (+51% potential, high confidence)" ] } ``` ### Validate Before Changing **Python:** ```python import requests response = requests.post( "https://api.crowterminal.com/api/agent/memory/client_123/validate", headers={ "Authorization": "Bearer ct_your_key", "Content-Type": "application/json" }, json={ "proposedChanges": [ {"field": "hookPatterns", "oldValue": ["POV"], "newValue": ["tutorial"]} ] } ) result = response.json() if result["validation"] == "blocked": print("BLOCKED! Don't make this change.") for warning in result["warnings"]: print(f" - {warning['message']}") ``` **Response:** ```json { "success": true, "validation": "blocked", "warnings": [ { "field": "hookPatterns", "severity": "critical", "message": "This exact value was tried 3 time(s) before with negative results", "evidence": { "versions": [5, 12, 19], "performanceDelta": "Engagement dropped -35% after v5" } } ], "recommendations": [ { "field": "hookPatterns", "recommendation": "Consider reverting to v28 value: [\"POV\",\"confession\"]", "basedOn": "v28 had 51% higher engagement" } ] } ``` --- ## Webhooks (Async Notifications) Receive real-time notifications when events occur. ### Register Webhook POST /api/agent/webhooks - Body: { url, events, secret? } - Returns: { id, secret } ### List Webhooks GET /api/agent/webhooks ### Update Webhook PATCH /api/agent/webhooks/:webhookId - Body: { url?, events?, isActive? } ### Delete Webhook DELETE /api/agent/webhooks/:webhookId ### Test Webhook POST /api/agent/webhooks/test - Body: { url, secret? } ### Available Events | Event | Description | |-------|-------------| | skill.updated | Client skill was updated | | skill.version_created | New skill version created | | data.ingested | Data was ingested | | validation.blocked | Proposed change was blocked | | posting.completed | Content posted successfully | | posting.failed | Content posting failed | ### Webhook Payload Format ```json { "event": "skill.updated", "timestamp": "2026-02-18T12:00:00Z", "webhookId": "wh_xxx", "agentId": "agent_xxx", "data": { /* event-specific data */ } } ``` ### Signature Verification All webhooks include `X-CrowTerminal-Signature` header: ``` sha256= ``` Verify using HMAC-SHA256 of raw body with your webhook secret. --- ## Status Page (Service Health) ### Service Status GET /api/agent/status - No auth required - Returns: overall status, component health, metrics ### Simple Ping GET /api/agent/status/ping - No auth required - Returns: { pong: true, timestamp } ### Component Status GET /api/agent/status/components - Detailed status of each component ### Historical Uptime GET /api/agent/status/uptime - 24h and 7d uptime percentages - Daily breakdown - Recent incidents ### Status History (for charting) GET /api/agent/status/history - 7-day uptime data points - Ready for visualization ### Recent Incidents GET /api/agent/status/incidents - List of recent incidents with duration and affected components ### Uptime Response Example ```json { "currentStatus": "operational", "uptime": { "last24h": { "percentage": "99.65%", "totalChecks": 288, "breakdown": { "operational": 287, "degraded": 1, "outage": 0 } }, "last7d": { "percentage": "99.82%", "daily": [ { "date": "2026-02-12", "uptimePercent": 100 }, { "date": "2026-02-13", "uptimePercent": 99.31 } ] } }, "recentIncidents": [] } ``` --- ## Contact - Email: agents@crowterminal.com - Docs: https://crowterminal.com/SKILL.md - MCP: https://crowterminal.com/.well-known/mcp.json - GitHub: https://github.com/WillNigri/FluxOps - Status: https://status.crowterminal.com --- *"Your agent's external hard drive. Because context windows aren't long-term memory."*