Developer Portal
The Developer Portal is where you manage your external service credentials (Credentials Vault), generate platform API keys, and monitor usage.
Credentials Vault
Store and manage API keys for external services like OpenAI, Stripe, Cloudflare, etc.
Why a Vault?
Without centralized credential management:
- Keys scattered across
.env files, Vercel, password managers
- No visibility into which keys are used where
- No expiration tracking or rotation reminders
- Risk of keys in git history or logs
The Credentials Vault solves this:
- Encrypted storage - Keys encrypted at rest with Supabase Vault
- Key hints only - Full key never retrievable after save
- Environment separation - Dev, staging, production isolated
- Usage tracking - See when credentials were last used
- Expiration alerts - Get notified before keys expire
Supported Providers
52 providers across 11 categories:
| Category | Providers |
|---|
| AI | OpenAI, Anthropic, Google AI, Replicate, Hugging Face, Groq, Together AI, Perplexity, Mistral, Cohere |
| Payments | Stripe, PayPal, Square, Wise |
| Email | Resend, SendGrid, Mailchimp, Postmark, AWS SES |
| Communications | Twilio, Vonage |
| Storage | Cloudflare R2, AWS S3, Supabase Storage, Cloudinary, Uploadthing |
| Database | Supabase, PlanetScale, Neon, Turso, Upstash |
| Infrastructure | Vercel, Cloudflare, AWS, Google Cloud, Fly.io, Railway, Render |
| Development | GitHub, GitLab, Linear, Figma |
| Productivity | Notion, Slack, Airtable, Google Workspace |
| Analytics | Mixpanel, Amplitude, PostHog, Segment |
| Monitoring | Sentry, Datadog, LogSnag |
| Ecommerce | Shopify, Stripe |
| Affiliate | Impact, Viator, Amazon Associates |
| Scraping | Apify, Browserless, ScrapingBee |
Adding a Credential
// POST /api/credentials
{
"provider_id": "uuid-of-openai",
"name": "Production OpenAI",
"environment": "production",
"credential": "sk-proj-xxxxxxxxxxxxx",
"scopes": ["chat", "embeddings", "images"]
}
Response:
{
"id": "uuid",
"name": "Production OpenAI",
"environment": "production",
"key_hint": "...xxxxx",
"provider": {
"name": "OpenAI",
"icon_url": "..."
}
}
The full credential is encrypted immediately. You cannot retrieve it later—only the last 6 characters (hint) are stored in plaintext.
Using Credentials
Credentials are used by:
- Jarvis - AI inference calls
- Automations - Scheduled workflows
- Edge Functions - Server-side API calls
// Server-side: Get decrypted credential
import { getCredential } from '@trendingsociety/db/credentials';
const openaiKey = await getCredential({
tenantId: 'xxx',
providerSlug: 'openai',
environment: 'production'
});
// Use with OpenAI SDK
const openai = new OpenAI({ apiKey: openaiKey });
Generate API keys to access Trending Engine APIs programmatically.
Key Types
| Environment | Prefix | Use Case |
|---|
| Sandbox | ts_test_ | Development, testing |
| Production | ts_live_ | Live applications |
Scopes
API keys can be scoped to specific operations:
| Scope | Access |
|---|
content:read | Read articles, sites |
content:write | Create, update, delete content |
jarvis:invoke | Call Jarvis API |
analytics:read | Read analytics data |
users:read | Read user data |
users:write | Manage users |
billing:read | View billing info |
Creating an API Key
// POST /api/api-keys
{
"name": "Mobile App - Production",
"environment": "production",
"scopes": ["content:read", "jarvis:invoke"],
"rate_limit_per_minute": 100,
"expires_at": "2026-01-01T00:00:00Z" // Optional
}
Response:
{
"id": "uuid",
"name": "Mobile App - Production",
"key": "ts_live_xxxxxxxxxxxxxxxxxxxxxxxx",
"key_prefix": "ts_live_xxx",
"scopes": ["content:read", "jarvis:invoke"],
"rate_limit_per_minute": 100
}
The full API key is shown only once at creation. Copy it immediately—it cannot be retrieved later.
Using Your API Key
Include in the Authorization header:
curl https://api.trendingsociety.com/v1/content \
-H "Authorization: Bearer ts_live_xxxxxxxx"
Or with SDK:
import { TrendingEngine } from '@trendingsociety/sdk';
const client = new TrendingEngine({
apiKey: process.env.TRENDING_ENGINE_API_KEY
});
const articles = await client.content.list({ limit: 10 });
Usage & Billing
Track API usage and manage quotas.
Usage Dashboard
View usage by:
- Time period - Daily, weekly, monthly
- API product - Content, Jarvis, Analytics, etc.
- Endpoint - Specific routes
- Status - Success vs. errors
Quotas & Limits
Each plan includes base quotas:
| Plan | Content API | Jarvis API | Analytics API |
|---|
| Free | 100/mo | 10K tokens/mo | 1K/mo |
| Pro | 5K/mo | 500K tokens/mo | 50K/mo |
| Business | 50K/mo | 5M tokens/mo | 500K/mo |
| Enterprise | Unlimited | Unlimited | Unlimited |
Overage Pricing
When you exceed quotas, overage rates apply:
| Product | Overage Rate |
|---|
| Content API | $0.05/request |
| Jarvis API | $0.00001/token |
| Analytics API | $0.001/request |
| Distribution API | $0.02/request |
| UCI Identity API | $0.10/request |
Usage Alerts
Configure alerts at threshold levels:
// POST /api/usage-alerts
{
"product_id": "uuid-of-jarvis",
"threshold_percent": 80,
"notification_type": "email",
"notification_target": "[email protected]"
}
You’ll receive notifications at 80%, 90%, and 100% of quota.
Webhooks
Receive real-time notifications when events occur.
Creating a Webhook
// POST /api/webhooks
{
"url": "https://your-app.com/webhooks/trending",
"events": [
"content.published",
"user.joined",
"api_key.created"
]
}
Response:
{
"id": "uuid",
"url": "https://your-app.com/webhooks/trending",
"events": ["content.published", "user.joined", "api_key.created"],
"secret": "whsec_xxxxxxxxxxxxxxxx"
}
Verifying Webhooks
All webhooks are signed with HMAC-SHA256:
import { createHmac } from 'crypto';
function verifyWebhook(payload: string, signature: string, secret: string) {
const expected = createHmac('sha256', secret)
.update(payload)
.digest('hex');
return `sha256=${expected}` === signature;
}
// In your handler
app.post('/webhooks/trending', (req, res) => {
const isValid = verifyWebhook(
JSON.stringify(req.body),
req.headers['x-trending-signature'],
process.env.WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
// Process webhook...
});
Webhook Payload
{
"id": "evt_xxxxx",
"type": "content.published",
"created_at": "2025-01-15T10:30:00Z",
"data": {
"article_id": "uuid",
"title": "10 AI Trends for 2025",
"site_id": "uuid",
"published_at": "2025-01-15T10:30:00Z"
}
}
Available Events
| Event | Description |
|---|
tenant.created | New tenant signed up |
tenant.updated | Tenant settings changed |
content.published | Article published |
content.updated | Article modified |
site.created | New site added |
site.deleted | Site removed |
user.invited | Team invite sent |
user.joined | User accepted invite |
api_key.created | New API key generated |
api_key.revoked | API key revoked |
Retry Policy
Failed deliveries are retried with exponential backoff:
- Attempt 1: Immediate
- Attempt 2: 1 minute
- Attempt 3: 5 minutes
- Attempt 4: 30 minutes
- Attempt 5: 2 hours
After 5 failures, the webhook is paused and you’re notified.