Integrations¶
Every external service is reached through a port interface in application/shared/ports/ and a concrete adapter in infrastructure/, wired in deps.factory.ts. Only environment-variable names are listed below — never set secret values in wrangler.toml; use wrangler secret put (see Development).
Summary¶
| Integration | Adapter | Purpose | Key env vars (names) |
|---|---|---|---|
| Pipedrive CRM | PipedriveCrmService |
Create leads + notes from submissions | PIPEDRIVE_API_TOKEN, PIPEDRIVE_DOMAIN, PIPEDRIVE_BCC, PIPEDRIVE_ENABLED |
| Mailgun | MailgunEmailService |
Transactional email | MAILGUN_API_KEY, MAILGUN_DOMAIN, SUPPORT_EMAIL_FROM, SUPPORT_EMAIL_TO, RESULTS_EMAIL_TO, SALES_MANAGER_EMAIL, PIPEDRIVE_BCC |
| V0 | V0PrototypeService |
AI prototype generation | V0_API_KEY |
| ClickUp | ClickupNotificationService |
Immediate lead alerts + sales-channel prototype notifications | CLICKUP_API_TOKEN, CLICKUP_TEAM_ID, SALES_CHANNEL_ID, LEAD_ALERT_CHANNEL_ID |
| LiteLLM | LiteLlmService |
Lead/spam/vendor classification | LITELLM_API_URL, LITELLM_API_KEY |
| Agno | AgnoAgentService |
Sales-chat agent (streaming) | AGNO_API_URL, AGNO_API_KEY |
| WordPress | CachedWordPressService / WordPressPostsService |
Blog content | WORDPRESS_POSTS_API |
| Google PageSpeed | pagespeed.service |
Diagnostic performance scores | PAGESPEED_API_KEY |
| Google reCAPTCHA | RecaptchaService |
Bot protection on public forms | SECRET_RECAPTCHA_KEY |
Pipedrive CRM¶
Automatic lead sync with custom field mapping. When PIPEDRIVE_ENABLED="false" the adapter no-ops as a success (no leadId), so the lead is still saved locally and downstream note/CC-email calls are skipped (they are guarded by if (lead.pipedriveLeadId)).
- Creates a Pipedrive lead from a form/chat submission, then adds a detailed note with all collected fields (service-specific notes for diagnostic, strategic advice, dedicated team, technology strategy, process automation).
- Resolves the lead's CC email (
getLeadCcEmail) so confirmation emails can BCC the CRM thread. - Custom field API keys (app type, project type, app name, app description) are documented in the repo
PIPEDRIVE.md. PIPEDRIVE_BCC(e.g.swapps@pipedrivemail.com) is BCC'd on contact/ticket emails for automatic email linking.
Env vars: PIPEDRIVE_API_TOKEN, PIPEDRIVE_DOMAIN, PIPEDRIVE_BCC, PIPEDRIVE_ENABLED.
Mailgun (email)¶
POST https://api.mailgun.net/v3/{domain}/messages via FormData, with a 10s timeout. Supports from, to, subject, text, html, optional bcc, click-tracking toggle (o:tracking-clicks), and file attachments.
Used for: prototype-ready notifications, service-specific confirmation emails, support-ticket confirmations (customer + support team), vendor decline emails. The sales manager is added to To (via combineToAddresses) and the CRM thread via BCC.
Env vars: MAILGUN_API_KEY, MAILGUN_DOMAIN, SUPPORT_EMAIL_FROM, SUPPORT_EMAIL_TO, RESULTS_EMAIL_TO, SALES_MANAGER_EMAIL, PIPEDRIVE_BCC.
V0 (prototype generation)¶
Wraps the v0-sdk client. Creates chats, polls deployment status, and recovers interrupted generations.
- Model tiers: applications use
v0-pro, landing pages and everything else usev0-mini(the SDK's typedv0-1.5-*ids are deprecated; the adapter casts to the current ids). - Async creation (
responseMode: 'async') returns a placeholder fast; the adapter caps a single attempt at 15s and retries once on transient failures (timeouts, 408/429/5xx), surfacing non-retryable statuses (400/401/403/404/422) immediately. - Streaming creation feeds the SSE progress flow; polling (
pollStatus) drives the background DO. The processor sendsBuildto accept V0 plan mode, and usesresumeMessage/sendContinueto recover interrupted messages.
Env var: V0_API_KEY.
ClickUp (notifications)¶
Posts notifications fire-and-forget so they never block the request or DO alarm cycle. New qualified leads go immediately to the configured direct system-to-Andrés channel (LEAD_ALERT_CHANNEL_ID), while prototype-generation started / completed / failed messages continue to use the sales channel (SALES_CHANNEL_ID). The new-lead alert includes the submitted contact information, source landing, available customer message, and—when a phone was supplied—a short Spanish Sandler-style WhatsApp first-touch template with the target SLA of under one business hour.
The ClickUp API token must belong to the system account that can post in the configured direct channel. The immediate alert is deliberately separate from /leads-seguimiento: it signals the first human touch only; it does not send email or schedule follow-ups, so the cadence remains the sole owner of subsequent contact.
Env vars: CLICKUP_API_TOKEN, CLICKUP_TEAM_ID, SALES_CHANNEL_ID, LEAD_ALERT_CHANNEL_ID.
LiteLLM (lead classification)¶
Calls a LiteLLM proxy (POST {url}/v1/chat/completions, model gemini-2.5-flash, temperature 0.1, 10s timeout) to classify each submission as lead, spam, or vendor with a confidence score and reasoning.
- Fails open: any error, empty/invalid response, or confidence
< 0.5defaults tolead. - The result is always attached to the stored lead; whether it filters is gated by
SPAM_FILTER_ENABLED/VENDOR_FILTER_ENABLED.
Env vars: LITELLM_API_URL, LITELLM_API_KEY (URL defaults to https://litellm.swapps.live).
Agno (sales-chat agent)¶
Powers /api/chat. The adapter speaks to the Agno service over both REST (run agent, list agents, session history) and a WebSocket for streaming.
- WebSocket upgrade is negotiated over the
http(s)://URL withUpgrade: websocket+X-API-Key(Cloudflare Workersfetchdoes not acceptws://). Stream events aretoken/done/error. - The worker re-streams these to the browser as SSE and persists the transcript to KV.
- The agent type used by the chat route is
swapps_leads.
Env vars: AGNO_API_URL, AGNO_API_KEY.
WordPress REST API (blog)¶
WordPressPostsService calls the WordPress REST API; CachedWordPressService wraps it with KV caching (posts_cache: prefix). The worker maps /api/posts* query params straight through to …/wp-json/wp/v2/....
- Source configured via
WORDPRESS_POSTS_API(defaulthttps://swapps.com/wp-json/wp/v2). - Cache can be bypassed per request with
?cache=false; purged via the authenticated cache endpoints.
Warning
A Cloudflare WAF/bot challenge on /wp-json/ blocks the server-side fetch (403 cf-mitigated: challenge), surfacing as EXTERNAL_SERVICE_ERROR / 502. Fix at the zone level with a WAF Skip rule scoped to Worker subrequests (cf.worker.upstream_zone ne "").
Env var: WORDPRESS_POSTS_API.
Google PageSpeed Insights (diagnostic)¶
/api/diagnostic/analyze runs PageSpeed against a validated URL (mobile/desktop) and caches results for 24h per URL+strategy.
Env var: PAGESPEED_API_KEY.
Google reCAPTCHA¶
RecaptchaService verifies tokens on public forms (POST /api/leads, /api/support/send, /api/support/tickets). Skipped in development and for trusted chat requests on /api/leads.
Env var: SECRET_RECAPTCHA_KEY.