Skip to main content

Spring Intelligence API

Spring Intelligence is Flow's AI-powered content research and generation engine. It automates signal discovery, relevance scoring, and content drafting based on your knowledge base and stance.

Overview

Spring Intelligence helps you:

  1. Discover signals - Monitor RSS feeds, URLs, and semantic searches
  2. Score relevance - AI-powered filtering against your knowledge base
  3. Generate drafts - Platform-specific content from high-relevance signals
  4. Track performance - Analytics on acceptance rate and edit distance

Architecture

Signal Sources → Ingestion → Relevance Engine → Draft Generation → Review Queue
↓ ↓ ↓ ↓ ↓
RSS/URL Extract Content LLM Scoring Knowledge+Stance Human Review

Authentication

All endpoints require authentication:

Authorization: Bearer flow_sk_live_abc123...

Knowledge Base

Your knowledge base defines who you are and what you build. It's used for:

  • Relevance scoring (is this signal relevant to us?)
  • Draft generation (what opinions should we inject?)

Get Knowledge Base

GET /api/spring/knowledge

Response (Not Configured)

{
"configured": false,
"knowledge": null,
"stance": null
}

Response (Configured)

{
"configured": true,
"knowledge": {
"productName": "Flow Social",
"productTagline": "The zen social media scheduler",
"productDescription": "A calm, beautiful platform for scheduling social posts",
"productFeatures": ["AI content generation", "Multi-platform posting"],
"valuePropositions": ["Save time", "Post consistently"],
"targetAudience": "Content creators and founders",
"idealCustomerProfile": "Solo founders with limited time",
"techStack": ["Cloudflare Workers", "React", "TypeScript"]
},
"stance": {
"hotTakes": ["Serverless is the future", "Quality over quantity"],
"loves": ["Developer experience", "Clean APIs"],
"hates": ["Bloated software", "Complexity for its own sake"],
"contrarianViews": ["Social media should be zen, not stressful"],
"toneKeywords": ["professional", "friendly", "technical"]
}
}

Create/Update Knowledge Base

PUT /api/spring/knowledge
Content-Type: application/json

{
"productName": "My Product",
"productTagline": "Best product ever",
"productDescription": "A detailed description",
"productFeatures": ["Feature 1", "Feature 2"],
"valuePropositions": ["Value 1", "Value 2"],
"targetAudience": "Developers",
"idealCustomerProfile": "Senior engineers at startups",
"techStack": ["Node.js", "React"]
}

Update Stance Only

PATCH /api/spring/knowledge/stance
Content-Type: application/json

{
"hotTakes": ["Hot take 1", "Hot take 2"],
"loves": ["Thing we love"],
"hates": ["Thing we hate"],
"contrarianViews": ["Contrarian view"],
"toneKeywords": ["professional", "witty"]
}

Signal Sources

Configure where Spring looks for content to react to.

List Sources

GET /api/spring/sources

Response

{
"sources": [
{
"id": "src_abc123",
"type": "rss",
"label": "Hacker News",
"config": { "url": "https://news.ycombinator.com/rss" },
"frequency": "hourly",
"isActive": true,
"lastChecked": 1706000000000
},
{
"id": "src_def456",
"type": "semantic_search",
"label": "Industry Pain Points",
"config": { "query": "social media scheduling problems" },
"frequency": "daily",
"isActive": true
}
],
"count": 2
}

Add Source

POST /api/spring/sources
Content-Type: application/json

{
"type": "rss",
"label": "TechCrunch",
"config": { "url": "https://techcrunch.com/feed/" },
"frequency": "hourly"
}

Source Types

TypeConfigDescription
rss{ url: string }RSS/Atom feed URL
url{ url: string }Direct webpage URL
semantic_search{ query: string }Semantic search query

Frequencies

  • hourly - Check every hour
  • daily - Check once per day (midnight UTC)
  • weekly - Check once per week (Sunday midnight UTC)

Update Source

PATCH /api/spring/sources/:id
Content-Type: application/json

{
"label": "Updated Label",
"frequency": "daily",
"isActive": false
}

Delete Source

DELETE /api/spring/sources/:id

Processed Signals

Signals are content items discovered from your sources and scored for relevance.

List Signals

GET /api/spring/signals
GET /api/spring/signals?status=relevant&limit=20

Query Parameters

ParameterTypeDescription
statusstringFilter by status: pending, relevant, discarded, used, expired
limitintegerMax signals to return (default: 50)

Response

{
"signals": [
{
"id": "sig_abc123",
"url": "https://example.com/article",
"title": "Industry News: Major Announcement",
"contentSummary": "Summary of the article...",
"relevanceScore": 85,
"relevanceReasoning": "Directly impacts target audience pain points",
"triggerType": "market_shift",
"status": "relevant",
"discoveredAt": 1706000000000
}
],
"count": 1
}

Relevance Scores

Score RangeMeaningAction
0-50NoiseAuto-discarded
51-79Weak signalLogged but not drafted
80-100High signalProceed to drafting

Trigger Types

TypeDescription
newsGeneral industry news
competitorCompetitor activity or announcement
market_shiftMarket trend or change
user_complaintUser pain point or problem
validationValidates your approach/thesis

Submit URL for Processing

Manually submit a URL to be processed.

POST /api/spring/signals/submit
Content-Type: application/json

{
"url": "https://example.com/interesting-article",
"title": "Optional title"
}

Response

{
"success": true,
"signalId": "sig_xyz789",
"message": "URL submitted for processing. It will be scored shortly."
}

Update Signal Status

PATCH /api/spring/signals/:id/status
Content-Type: application/json

{
"status": "used"
}

Draft Generation

Generate platform-specific content from a signal.

Generate Draft

POST /api/spring/signals/:id/draft

Response

{
"success": true,
"signal": {
"id": "sig_abc123",
"title": "Industry News: Major Announcement",
"url": "https://example.com/article",
"relevanceScore": 85,
"triggerType": "market_shift"
},
"drafts": {
"twitter": "The market is shifting toward [topic]. This is exactly why we built [product]. Here's my take: [opinion based on stance]. What do you think?",
"linkedin": "I've been watching [topic] closely for the past few months...\n\n[Longer form content with paragraphs]\n\nWhat's your perspective on this shift?"
},
"quality": {
"score": 0.85,
"reasoning": "Strong connection to knowledge base and clear stance integration"
}
}

Requirements

  • Knowledge base must be configured
  • ANTHROPIC_API_KEY environment variable must be set

Analytics

Track your Spring Intelligence performance.

Get Analytics

GET /api/spring/analytics
GET /api/spring/analytics?days=30

Response

{
"period": {
"start": 1703000000000,
"end": 1706000000000,
"days": 30
},
"signals": {
"discovered": 150,
"relevant": 45,
"weak": 60,
"discarded": 45,
"used": 20
},
"drafts": {
"generated": 45,
"approved": 18,
"rejected": 12,
"edited": 15
},
"quality": {
"avgRelevanceScore": 72,
"avgEditDistance": 15,
"acceptanceRate": 40.0
},
"dailyBreakdown": [
{ "date": "2024-01-20", "signalsDiscovered": 5, "draftsGenerated": 2, "draftsApproved": 1 },
{ "date": "2024-01-19", "signalsDiscovered": 8, "draftsGenerated": 3, "draftsApproved": 2 }
]
}

Track Events

Track draft approval/rejection for analytics.

POST /api/spring/analytics/track
Content-Type: application/json

{
"eventType": "draft_approved",
"signalId": "sig_abc123",
"editDistance": 12
}

Event Types

EventDescription
draft_generatedDraft was generated from signal
draft_approvedDraft was approved (include editDistance)
draft_rejectedDraft was rejected (include reason)
post_publishedContent was published (include platform)

Check Content Drift

Detect if you're repeating topics too frequently.

GET /api/spring/analytics/drift?topic=serverless&days=7

Response

{
"hasDrift": true,
"similarTopics": [
"Serverless computing trends",
"Why serverless matters"
],
"lastMentioned": "2024-01-18T10:00:00Z"
}

Cron Worker

Spring Intelligence includes a scheduled worker for automatic signal ingestion.

Deployment

Deploy the signal ingestor as a separate Cloudflare Worker:

wrangler deploy -c wrangler.worker.toml

Schedule

By default, the worker runs hourly to:

  1. Fetch sources due for checking
  2. Ingest content from RSS feeds and URLs
  3. Score relevance against your knowledge base
  4. Store high-relevance signals

SDK Examples

TypeScript SDK

import { Flow } from '@flowdev/sdk';

const flow = new Flow('flow_sk_live_...');

// Setup knowledge base
await flow.spring.updateKnowledge({
productName: 'My Product',
productFeatures: ['Feature 1', 'Feature 2'],
});

// Add signal source
await flow.spring.addSource({
type: 'rss',
label: 'Tech News',
config: { url: 'https://example.com/feed.xml' },
frequency: 'hourly',
});

// Get relevant signals
const { signals } = await flow.spring.getSignals({ status: 'relevant' });

// Generate draft from signal
const { drafts } = await flow.spring.generateDraft(signals[0].id);
console.log('Twitter:', drafts.twitter);
console.log('LinkedIn:', drafts.linkedin);

// Track approval
await flow.spring.trackEvent({
eventType: 'draft_approved',
signalId: signals[0].id,
editDistance: 10,
});

Python SDK

from flow_sdk import Flow

flow = Flow('flow_sk_live_...')

# Setup knowledge
flow.spring.update_knowledge(
product_name='My Product',
product_features=['Feature 1', 'Feature 2']
)

# Get signals
signals = flow.spring.get_signals(status='relevant')

# Generate draft
drafts = flow.spring.generate_draft(signals[0]['id'])
print(f"Twitter: {drafts['twitter']}")

Best Practices

Knowledge Base

  1. Be specific about your target audience and ICP
  2. Include your tech stack for technical relevance matching
  3. Define clear hot takes for opinionated content generation

Signal Sources

  1. Start with 3-5 high-quality sources rather than many mediocre ones
  2. Use semantic search for pain point discovery
  3. Monitor competitor changelogs for reactive content opportunities

Content Quality

  1. Review and edit AI-generated drafts before publishing
  2. Track edit distance to improve generation over time
  3. Check for content drift to avoid repetitive topics

Performance Targets

MetricTargetDescription
Acceptance Rate>30%% of drafts approved for publishing
Edit Distance<20%% of characters changed in approved drafts
Relevance Score>75 avgAverage score of processed signals

Error Codes

StatusErrorDescription
400Knowledge base not configuredSetup knowledge before generating drafts
400URL already processedSignal deduplication in effect
400Invalid source typeMust be rss, url, or semantic_search
500AI generation not configuredANTHROPIC_API_KEY not set
500Failed to generate draftsLLM API error