Services
import { Aside } from ‘@astrojs/starlight/components’;
A WebsiteService is one provisioned integration attached to a Website. The GitHub repo is a service. The Vercel project is a service. A Shopify store, an OpenRouter key, a Resend domain, a TikTok channel — each is a separate service row.
Data shape
Section titled “Data shape”type ServiceType = | "github" | "vercel" | "openrouter" | "resend" | "bookings" | "seo" | "commerce" | "channel_tiktok" | "channel_facebook" | "channel_pinterest" | "channel_google" | "channel_marketplace_connect";
interface WebsiteService { websiteId: string; serviceType: ServiceType; externalId: string; // the integration's id for this resource externalUrl?: string; // a link to view it in the vendor's dashboard secretArn?: string; // pointer to Secrets Manager metadata?: Record<string, unknown>; createdAt: string;}(websiteId, serviceType) is the primary key — at most one row per type
per Website. Channels are an exception via the typed variants
(channel_tiktok, channel_facebook, …); each is its own type.
The platform-agnostic types
Section titled “The platform-agnostic types”commerce and channel_* are platform-agnostic. The actual backend is
recorded on metadata.platform:
{ websiteId: "wb_01J7...", serviceType: "commerce", externalId: "acme.myshopify.com", metadata: { platform: "shopify" }}Today every commerce row has platform: "shopify", but the type
deliberately doesn’t bake that in — if a future adapter ships
(BigCommerce, Medusa), existing data and the surrounding type system
don’t need to change.
Where service state lives
Section titled “Where service state lives”| Service | What externalId holds | What’s in metadata |
|---|---|---|
github | repo full name (org/client-slug) | default branch, last commit |
vercel | project id | production deployment id, deploy url |
openrouter | key id | usage stats snapshot |
resend | domain id | DNS verification status |
bookings | cal.com username | brand color, public URL |
seo | tier name | capability snapshot, scan results, GEO probes |
commerce | platform’s canonical store id | platform, currency, scopes granted |
channel_* | channel handle ("tiktok", etc.) | platform, install status, publication id |
OAuth tokens are NOT in the row
Section titled “OAuth tokens are NOT in the row”secretArn points to Secrets Manager. Access tokens (Shopify
Admin API tokens, etc.) live there, not in the WebsiteService row.
Reasons: rotation, audit, fine-grained IAM, and not putting credentials
in a row that gets dumped in console logs.
To use a token, fetch it from Secrets Manager via the secretArn. The
integrations layer (packages/api/src/integrations/*.ts) handles this
for you.
Reading services
Section titled “Reading services”# CLI doesn't currently surface this; use SDK:const { services } = await vc.websites.services("wb_01J7...");for (const s of services) { console.log(s.serviceType, s.externalUrl);}The REST endpoint is GET /v1/websites/:id/services.
Service logs
Section titled “Service logs”Recent activity per service (deployments, AI calls, scan runs) lives on a sibling endpoint:
const { logs } = await vc.websites.logs("wb_01J7...", "vercel");Each integration emits its own log shape — see the REST API reference for the exact union.
Creating services
Section titled “Creating services”You don’t typically create service rows directly. Two patterns:
- Provisioning the Website creates the always-on services —
github+vercelare always created during initial provisioning, never separately. - Toggling features creates optional services —
vantage websites features <id> --openrouterprovisions the OpenRouter key + creates the service row in one step.
The exceptions are OAuth-based services (Shopify, channels) which are created when the merchant completes an OAuth flow through the portal, not by an API call.
Tearing down services
Section titled “Tearing down services”Service teardown is per-feature and happens automatically when:
- The Website is deleted (every service torn down)
- A feature flag flips false (only that service torn down)
- A Shopify app is uninstalled (
commerce+ dependentchannel_*rows removed via webhook)
See also
Section titled “See also”- Blueprint — the visual view of a Website’s services
- Provisioning — when service rows get created
- Commerce + channels — the special case of multi-row services