Wire a governed connection
Stripe, Twilio, SendGrid, your internal gRPC service — every external integration is a typed, governed connection.
Authored code never opens raw sockets, never stores plaintext secrets, never makes ungoverned outbound calls. Every external integration is modeled as a governed connection — a typed platform entity with secret references, capability descriptors, egress policy, and observability hooks.
Connection types
Vadyl ships first-class connection types for common integrations:
http— generic HTTP / OAuth2 / OAuth1llm— model inference adaptersemail— SendGrid, Resend, SMTPsms— Twilio, MessageBirdpayment— Stripe, Adyen, Paddlebroker— Kafka, NATS, RabbitMQsearch— Elasticsearch, Algolia, Typesensekms— AWS KMS, Azure Key Vault, GCP KMSgrpc— internal gRPC servicescustom— for anything not in the catalog (declarative bundle or Wasm-authored)
Define a connection
// src/connections/stripe.ts
import { connection, secret } from "@vadyl/sdk";
export default connection.define("stripe", {
type: "payment",
vendor: "stripe",
baseUrl: "https://api.stripe.com",
auth: {
kind: "bearer",
token: secret.ref("STRIPE_SECRET_KEY"), // never inline a string
},
egress: {
allowedHosts: ["api.stripe.com"],
timeoutMs: 30_000,
},
capabilities: {
operations: ["createCharge", "createCustomer", "refund", "listCharges"],
requiresIdempotencyKey: true,
},
observability: {
redactRequestFields: ["card.number", "card.cvc"],
redactResponseFields: ["payment_method_details"],
},
});Use it from authored code
// src/handlers/orders/charge.ts
export default handler.core(async (ctx, input: { orderId: string }) => {
const order = await ctx.entities.Order.read(input.orderId);
// The SDK is typed against the connection's declared operations
const charge = await ctx.connections.stripe.createCharge({
amount: order.total,
currency: order.currency,
customer: order.customerId,
idempotencyKey: `charge:${order.id}`,
});
await ctx.entities.Order.update(order.id, {
status: "paid",
chargeId: charge.id,
});
return { ok: true, chargeId: charge.id };
});Secret references
Secrets are resolved through the project's ISecretProvider binding — environment variables in dev, AWS Secrets Manager / Azure Key Vault / GCP Secret Manager / a custom KMS in production. The plaintext value never appears on connection records, never appears in observability data, never appears in branching diffs.
Egress policy
Every governed connection declares an allowlist of egress hosts. Calls to non-allowlisted hosts fail closed with a typed error. This is enforced at the runtime bridge level — not by you remembering to add a check.
Per-environment overrides
Use a different Stripe account in staging vs production:
// vadyl.config.ts
environments: {
staging: { secrets: { STRIPE_SECRET_KEY: "stripe-test-key" } },
production: { secrets: { STRIPE_SECRET_KEY: "stripe-live-key" } },
},Observability
Every connection invocation produces an operational trail with request/response sizes, latency, status, and redacted payload. Failures classify by typed error kind (auth, rate-limited, timeout, provider-error, network) — never by string-matching exception messages.
Managed HTTP escape hatch
For ad-hoc integrations not yet first-class, use ctx.http — a managed generic HTTP client that still flows through allowed-host enforcement, secret references, and audit. Raw fetch() from authored code is rejected at compile time.