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 use v0-mini (the SDK's typed v0-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 sends Build to accept V0 plan mode, and uses resumeMessage / sendContinue to 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.5 defaults to lead.
  • 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 with Upgrade: websocket + X-API-Key (Cloudflare Workers fetch does not accept ws://). Stream events are token / 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 (default https://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.