Most SaaS integrations are built one at a time. Slack connector, Stripe connector, HubSpot connector — each one is weeks of custom code, OAuth flows, and webhook handling.
We took a different approach: a single OpenAPI connector that lets our AI agents talk to any SaaS with a spec file.
The Problem
Our platform (S.C.A.L.A.) serves 20 different industries — restaurants, hotels, property management, retail, and more. Each vertical needs different integrations:
- Restaurants need POS + reservation systems
- Hotels need PMS + channel managers
- Retail needs inventory + e-commerce platforms
Building 50+ custom integrations was not an option for a bootstrapped team.
The Architecture
User prompt → AI Agent → Tool Dispatcher → OpenAPI Connector → External SaaS
↓
spec_url or spec_json
auth_type (api_key | bearer | basic | oauth2)
encrypted credentials (AES-256)
Step 1: Import any OpenAPI spec
Users paste a spec URL or upload JSON. We validate it, extract endpoints, and store the schema:
const createConnectorSchema = z.object({
name: z.string().min(1).max(200),
spec_url: z.string().url().max(2048).optional(),
spec_json: z.record(z.string(), z.unknown()).optional(),
auth_type: z.enum(['none', 'api_key', 'bearer', 'basic', 'oauth2']),
auth_config: z.object({
api_key: z.string().max(500).optional(),
api_key_header: z.string().max(100).optional(),
bearer_token: z.string().max(2000).optional(),
// ... other auth types
}).optional(),
});
Step 2: AI agent discovers available actions
When a user says "check my inventory levels", the agent:
- Looks at all connected OpenAPI specs
- Matches the intent to available endpoints (semantic search)
- Builds the API call with correct parameters
- Executes via SSRF-protected fetch
Step 3: Credentials never leave the vault
All secrets are encrypted at rest with AES-256. The connector decrypts only at call time, in-memory, never logged:
import { encryptSecret, decryptSecret } from '../lib/encryption.js';
// Store encrypted
const encrypted = encryptSecret(rawApiKey);
// Decrypt only when calling
const key = decryptSecret(encrypted);
Security: SSRF Protection
The biggest risk with a universal connector is SSRF — a malicious spec could point to internal services. We validate every URL before fetching:
import { validateUrlSSRF, safeFetch } from '../lib/ssrf.js';
// Blocks: localhost, 169.254.x.x, 10.x.x.x, internal DNS
const validated = validateUrlSSRF(targetUrl);
const response = await safeFetch(validated, { timeout: 15_000 });
Rate Limiting
Each connector gets its own rate limit bucket. We use per-key in-process limiting (1000 req/min) on top of the global IP-based limiter:
API Key → SHA-256 hash → lookup in api_keys table → scope check → rate limit bucket → execute
What This Enables
With this pattern, adding a new SaaS integration takes minutes, not weeks:
- User pastes the OpenAPI spec URL
- Sets auth type + credentials
- The AI agent immediately knows how to use every endpoint
We've seen users connect everything from Shopify to custom ERPs — all through the same universal connector.
Lessons Learned
OpenAPI specs are inconsistent — many have wrong types, missing required fields, or incomplete auth docs. Build defensive parsing.
AI needs curated endpoints — showing the agent ALL 200 endpoints of a large API is noise. Let users pin the 5-10 they actually need.
Timeout aggressively — external APIs are slow. 15-second hard timeout prevents one bad call from blocking the agent loop.
Log everything except secrets — when debugging "why didn't the agent call Shopify correctly?", you need the full request chain minus credentials.
Try It
S.C.A.L.A. is an agentic AI platform with 20 industry-specific agents. The OpenAPI connector is available on the Scale plan.
- Website: get-scala.com
- Open-source WhatsApp agent: SARA on GitHub
- Open-source RE feasibility agent: LandIQ on GitHub
API docs and sandbox available at get-scala.com/api-docs.
Building AI agents for real businesses, not demos. Follow for more from the trenches.
Top comments (0)