Appearance
Historical snapshot archived 2026-09-25. This records an earlier review or plan, not current implementation or live ticket state. For current work, follow root AGENTS.md, the relevant BloxClips skill, and owning repository source/tests. Preserve approved decisions as evidence; verify their present authority before acting.
External Integrations
Every external system involved in submission behavior.
1. Discord
Purpose
- User authentication (Discord OAuth)
- In-app notifications (UserNotification → Discord DM via bot? No — in-app only)
- Campaign expiry reports (DM to user via UserChannel)
- Admin audit log context (adminId = Discord ID)
- Legacy: Submission approval queue (removed)
Where Invoked
src/index.ts— Bot entry pointsrc/scheduler.ts:61-150— Campaign expiry DM reportssrc/utils/notifications.ts—createUserNotification(in-app only)src/utils/discordClient.ts— REST API client
Configuration
| Env Var | Description |
|---|---|
DISCORD_BOT_TOKEN | Bot token for REST API |
DISCORD_CLIENT_ID | OAuth client ID |
DISCORD_CLIENT_SECRET | OAuth secret |
GUILD_CONFIG (DB) | Channels, roles |
Inputs/Outputs
- Input: User Discord ID, channel IDs, role IDs
- Output: DM messages (expiry reports), audit log actor IDs
Failure Behavior
- Expiry DM fails → logged, campaign still marked inactive
- OAuth fails → user can't login
Submission Data Affected
Submission.userId= Discord ID (legacy)Submission.messageId= Legacy approval message ID (unused)AdminAuditLog.adminId= Discord ID
Related Files
src/index.ts,src/scheduler.ts,src/utils/discordClient.ts,src/utils/notifications.ts
2. Apify (TikTok & Instagram Scraping)
Purpose
Scrape view counts, likes, comments, metadata for TikTok/Instagram videos
Where Invoked
src/api/routes/submissions.ts:377-427— Submission create (first scrape)src/utils/tracking/runTrackingTick.ts:237-285— Continuous ticksrc/utils/payouts/rescrape.ts:259-288— Payout rescrape
Configuration
| Env Var | Description |
|---|---|
APIFY_TOKEN | Apify API token |
APIFY_TIKTOK_ACTOR_ID | Actor ID (default: clockworks/tiktok-scraper) |
APIFY_INSTAGRAM_ACTOR_ID | Actor ID (default: apify/instagram-scraper) |
Inputs
- Array of video URLs
userKey(for cost tracking)
Outputs
typescript
ScrapeOk: {
url, id, ok: true,
views, likes, comments,
videoTitle, previewVideoUrl, previewImageUrl,
creatorHandle, creatorAccountId, postedAt
}
ScrapeFail: {url, id, ok: false, reason}Failure Behavior
- Actor run failed → all URLs return
SCRAPE_FAILED - Video not found/private →
VIDEO_DELETED/VIDEO_PRIVATE - Rate limit → run fails, retry next tick (24h backoff)
- Cost cap →
costTracker.tsrecords usage, no hard block
Submission Data Affected
initialViews,currentViews,initialLikes,currentLikes,currentCommentsvideoTitle,previewVideoUrl,previewImageUrlcreatorHandle,creatorAccountId,postedAtconsecutiveScrapeFailures(incremented on fail)frozenViewCount(via budget clamp)
Cost Tracking
File: src/utils/scrapers/costTracker.ts
Records: {userKey, source: 'tiktok'|'instagram', rows: N} per batch
Related Files
src/utils/scrapers/apify.ts,src/utils/tracking/runTrackingTick.ts,src/utils/payouts/rescrape.ts
3. YouTube Data API v3
Purpose
Scrape YouTube video metadata (views, likes, comments, title, channel)
Where Invoked
src/api/routes/submissions.ts:350-375— Submission createsrc/utils/tracking/runTrackingTick.ts:201-235— Continuous ticksrc/utils/payouts/rescrape.ts:177-226— Payout rescrape
Configuration
| Env Var | Description |
|---|---|
YOUTUBE_API_KEY | YouTube Data API v3 key |
Inputs
- Array of video IDs (extracted from URLs)
Outputs
typescript
{
views, likes, comments,
title, creatorHandle, creatorAccountId (channelId),
uploadDate, duration
}Failure Behavior
- Quota exceeded → batch fails, all videos
SCRAPE_FAILED - Video not found → individual
VIDEO_DELETED - Network error → batch fails, retry next tick
Submission Data Affected
- Same as Apify +
duration(YouTube provides) isShortdetection viaisYouTubeShort(url, duration)
Related Files
src/utils/youtube.ts,src/utils/tracking/runTrackingTick.ts,src/utils/payouts/rescrape.ts
4. Stripe (Payouts)
Purpose
Primary payout rail (bank transfers via Stripe Connect)
Where Invoked
src/utils/rails/dispatcher.ts—dispatchPayoutfor method=stripesrc/api/routes/stripe.ts— Connect onboarding, webhookssrc/api/routes/adminPayoutReview.ts:781— Send payout
Configuration
| Env Var | Description |
|---|---|
STRIPE_SECRET_KEY | Stripe secret key |
STRIPE_WEBHOOK_SECRET | Webhook signing secret |
STRIPE_PAYOUT_SURCHARGE_BPS | Surcharge basis points (default 250 = 2.5%) |
Flow
- User completes Stripe Connect onboarding →
StripeAccount.onboardingComplete=true,payoutsEnabled=true - Payout approved →
AWAITING_SEND - Admin clicks Send (TOTP) →
dispatchPayout→ Stripe Transfer - Webhook
transfer.paid→Payout.COMPLETED
Failure Behavior
- Transfer fails →
FAILED, revert paid-totals, reverse affiliate - Idempotency key = payoutId (prevents double-send)
Submission Data Affected
Payout.stripeTransferIdPayout.status→ COMPLETED/FAILEDSubmission.paidViewsTotal,paidAmountTotal(bumped on approve, reverted on terminal fail)
5. PayPal (Payouts)
Purpose
Alternative payout rail (PayPal Payouts API)
Where Invoked
src/utils/rails/dispatcher.ts— method=paypalsrc/api/routes/paypal.ts— OAuth connect, webhookssrc/api/routes/adminPaypal.ts— Admin PayPal management
Configuration
| Env Var | Description |
|---|---|
PAYPAL_CLIENT_ID | PayPal client ID |
PAYPAL_CLIENT_SECRET | PayPal secret |
PAYPAL_PAYOUT_VOLUME_CAP_USD | Daily volume cap (Phase 7b) |
PAYPAL_MODE | mock or live |
Failure Behavior
- Circuit breaker: 3 failures →
paypalCircuitOpenedAt, all PayPal sends fail-fast until admin clears - Volume cap exceeded → reject new PayPal payouts
- Mock mode → no real money moves
6. NowPayments (USDT Payouts)
Purpose
Crypto payout rail (USDT TRC-20)
Where Invoked
src/utils/rails/dispatcher.ts— method=usdtsrc/utils/nowpayments/client.ts— NowPayments APIsrc/api/routes/usdt.ts— Wallet management
Configuration
| Env Var | Description |
|---|---|
NOWPAYMENTS_API_KEY | NowPayments API key |
USDT_NETWORK | TRC20 (hardcoded) |
Failure Behavior
- Network fee recorded in
Payout.usdtNetworkFee - On-chain tx hash in
Payout.onChainTxHash
7. Resend (Email)
Purpose
Transactional emails (campaign launch, payout notifications, tax forms)
Where Invoked
src/utils/email.ts—sendCampaignLaunchEmail,sendCampaignUpdateEmail,sendAdminWarningEmailsrc/utils/notifications.ts—notifyPayoutSent,notifyPayoutRejected(if email opted in)
Configuration
| Env Var | Description |
|---|---|
RESEND_API_KEY | Resend API key |
EMAIL_FROM | From address |
8. Tax1099 (Tax Compliance)
Purpose
W-9/W-8BEN verification, TIN matching, 1099-NEC filing
Where Invoked
src/utils/tax1099/client.ts— Tax1099 APIsrc/utils/tax/taxForm.ts— Form lifecyclesrc/api/routes/taxForms.ts— User tax form submissionsrc/api/routes/adminTaxForms.ts— Admin review
Configuration
| Env Var | Description |
|---|---|
TAX1099_API_KEY | Tax1099 API key |
TAX1099_API_SECRET | Tax1099 secret |
9. Roblox (Game Data)
Purpose
Game thumbnail, title, player count for campaigns
Where Invoked
src/utils/roblox.ts—getGameInfo,getGameThumbnailsrc/scheduler.ts:62— Campaign expiry thumbnailsrc/api/routes/admin.ts:48— Campaign thumbnail resolution
Configuration
None (public Roblox APIs)
10. Turnstile (CAPTCHA)
Purpose
Contact form spam protection
Where Invoked
src/api/routes/contact.ts— Contact form validation
Configuration
| Env Var | Description |
|---|---|
TURNSTILE_SECRET_KEY | Cloudflare Turnstile secret |
11. S3/R2 (File Storage)
Purpose
Tax form PDFs, video previews (if stored)
Where Invoked
src/utils/storage/r2.ts— Cloudflare R2src/utils/storage/local.ts— Local devsrc/utils/storage/tamperDetect.ts— PDF integrity
Configuration
| Env Var | Description |
|---|---|
R2_ACCOUNT_ID | Cloudflare account ID |
R2_ACCESS_KEY_ID | R2 access key |
R2_SECRET_ACCESS_KEY | R2 secret |
R2_BUCKET | Bucket name |
Summary Table
| Integration | Auth | Used By Submissions | Critical Path |
|---|---|---|---|
| Discord | Bot token | Notifications, expiry reports | No (legacy approval removed) |
| Apify | API token | TikTok/IG scraping | Yes — metrics |
| YouTube Data API | API key | YouTube scraping | Yes — metrics |
| Stripe | Secret key | Payout dispatch | Yes — payouts |
| PayPal | OAuth | Payout dispatch | Yes — payouts |
| NowPayments | API key | USDT payouts | Yes — payouts |
| Resend | API key | Emails | No |
| Tax1099 | API key | Tax forms | No (payout gate) |
| Roblox | None | Campaign data | No |
| Turnstile | Secret | Contact form | No |
| R2 | Credentials | PDF storage | No |