Core concepts
Model aliases
Your names for models, not the provider's.
Your customers call acme/smart, not anthropic/claude-sonnet-4. The alias is the indirection that lets you change provider, change model, or run a fallback without your customers noticing or your prices moving.
acme/smart → anthropic/claude-sonnet-4
acme/fast → anthropic/claude-haiku-4.5
acme/vision → openai/gpt-5-visionCreate an alias
seams models add acme/smart --source anthropic/claude-sonnet-4
# ok acme/smart → anthropic/claude-sonnet-4import { Seams } from "@ourseams/sdk"
const seams = new Seams({ apiKey: process.env.SEAMS_API_KEY! })
await seams.models.add("acme/smart", {
sources: [{ provider: "anthropic", model: "claude-sonnet-4" }],
})import os
from seams import Seams, models
seams = Seams(api_key=os.environ["SEAMS_API_KEY"])
seams.models.add(
"acme/smart",
sources=[models.AddModelSource(provider="anthropic", model="claude-sonnet-4")],
)Swap the source, pause, resume
The same name with a different source is a swap; clients keep calling acme/smart. Disable stops serving without deleting the name; enable brings it back.
seams models add acme/smart --source openai/gpt-5
seams models disable acme/smart
seams models enable acme/smart
seams models show acme/smart
seams models rm acme/smart --yesawait seams.models.add("acme/smart", {
sources: [{ provider: "openai", model: "gpt-5" }],
})
await seams.models.disable("acme/smart")
await seams.models.enable("acme/smart")
await seams.models.show("acme/smart")
await seams.models.rm("acme/smart")seams.models.add(
"acme/smart",
sources=[models.AddModelSource(provider="openai", model="gpt-5")],
)
seams.models.disable("acme/smart")
seams.models.enable("acme/smart")
seams.models.show("acme/smart")
seams.models.rm("acme/smart")What an end user sees
Aliases only. Usage rows and the portal show your name for the model; which provider served a call never crosses that boundary. The client keeps calling your name, any inbound wire:
await client.chat.completions.create({
model: "acme/smart",
messages: [{ role: "user", content: "Summarise the ticket" }],
})await client.messages.create({
model: "acme/smart",
max_tokens: 1024,
messages: [{ role: "user", content: "Summarise the ticket" }],
})await client.models.generateContent({
model: "acme/smart",
contents: "Summarise the ticket",
})curl https://<app>.gw.ourseams.com/v1/chat/completions \
-H "Authorization: Bearer ak_acme_…" \
-H "Content-Type: application/json" \
-d '{
"model": "acme/smart",
"messages": [{ "role": "user", "content": "Summarise the ticket" }]
}'This is enforced at the response boundary, not by convention. A usage row that leaked a provider model id would be the bug this indirection exists to prevent.