Skip to main content
# Before
from merge_gateway import MergeGateway
import os

client = MergeGateway(api_key=os.environ["MERGE_GATEWAY_API_KEY"])

response = client.responses.create(
    model="openai/gpt-4o",
    input=[{"type": "message", "role": "user", "content": "Say hello in one word"}],
    project_id="summarizer",
)

# After
from openai import OpenAI
import os

client = OpenAI(
    base_url="https://api.concentrate.ai/v1",
    api_key=os.environ["CONCENTRATE_API_KEY"],
)

response = client.responses.create(
    model="openai/gpt-4o",
    input=[{"type": "message", "role": "user", "content": "Say hello in one word"}],
)

Prerequisites

1

A Concentrate AI account with an active API key

Sign up or log in at concentrate.ai and create an API key. Your key should start with sk-cn-v1-.
2

An existing Merge Gateway integration

This guide assumes you are calling Merge Gateway from the merge-gateway-sdk, the OpenAI SDK, the Anthropic SDK, the Vercel AI SDK provider, fetch, requests, or another HTTP client.

Quick Start for Claude Code users

If you use Claude Code, you can install a skill that walks through this migration interactively. It searches your project for Merge Gateway usage, collapses the per-SDK base URLs, strips Merge-specific fields and headers, decomposes routing policies, maps model slugs, and generates a verification script. Drop the skill into your ~/.claude/skills/ directory:
mkdir -p ~/.claude/skills/migrate-merge && \
  curl -fsSL https://concentrate.ai/scripts/migrate-merge.md \
  -o ~/.claude/skills/migrate-merge/SKILL.md
Then start a Claude Code session in your project and ask it to “migrate from Merge Gateway to Concentrate” or run /migrate-merge. Claude will load the skill and run the steps.

Step 1: Update Your Environment Variables

Replace your Merge key (and any BYOK provider keys) with a single Concentrate key:
# Before
export MERGE_GATEWAY_API_KEY="mg_..."
export BASE_URL="https://api-gateway.merge.dev/v1/openai"

# After
export CONCENTRATE_API_KEY="sk-cn-v1-..."
export BASE_URL="https://api.concentrate.ai/v1"
If you ran Merge in BYOK mode, you no longer need OPENAI_API_KEY, ANTHROPIC_API_KEY, AWS credentials, or any other upstream provider key. Concentrate owns those credentials. Comment them out (don’t delete) until you’ve verified the migration end-to-end, then remove them.

Step 2: Update Your Client

The two big changes are collapsing the per-SDK base URL onto https://api.concentrate.ai/v1 and dropping Merge-specific fields and headers. If you were using the native merge-gateway-sdk, swap to the OpenAI SDK pointed at Concentrate. Concentrate does not ship a dedicated SDK because the OpenAI-compatible shape covers every endpoint.
# Before (native merge-gateway-sdk)
from merge_gateway import MergeGateway

client = MergeGateway(api_key=os.environ["MERGE_GATEWAY_API_KEY"])

# After (Concentrate)
from openai import OpenAI
import os

client = OpenAI(
    base_url="https://api.concentrate.ai/v1",
    api_key=os.environ["CONCENTRATE_API_KEY"],
)

response = client.chat.completions.create(
    model="anthropic/claude-opus-4-6",
    messages=[{"role": "user", "content": "Say hello in one word"}],
)
print(response.choices[0].message.content)

Step 3: Remove Merge-Specific Fields and Headers

None of Merge Gateway’s custom request fields or headers carry over to Concentrate, so they should come out. They’re dead weight in your client config and mislead future readers. Expand the tables below for the full mapping if any of these are in your code.
Merge fieldConcentrate replacement
project_idDrop. Issue per-project keys (or per-team / per-org keys); analytics roll up by whichever key, team, or org the request was made with. No per-request scoping field
tagsDrop. Use the key/team/org hierarchy for attribution. No per-request tagging
routing_policy_idDrop. Express routing as routing.model.fallbacks / routing.provider.fallbacks body params, or model: "auto". See Step 4
vendor, vendors (vendor routing / ordered vendor list)Drop. Pin via the model slug (provider/model-id), or order providers with routing.provider.fallbacks
include_routing_metadataDrop. The resolved provider is recorded per request in the dashboard
model: "default_routing"model: "auto" with explicit routing.model.sort (cost / latency / performance)
Merge supports two transports each for project scoping and tags. Project scoping: a project_id request-body field (canonical, used by both the Responses API schema and the Continue.dev guide, the latter via requestOptions.extraBodyProperties) and an X-Project-Id header. Tags: a tags request-body field (Responses API schema) and an X-Merge-Tags header. There is no deprecation notice for the header forms in the Merge changelog. Search your code for all four forms. None carries over to Concentrate.
Merge headerConcentrate replacement
Authorization: Bearer mg_...Standard Authorization: Bearer sk-cn-v1-...
X-Project-IdDrop. Per-key / team / org scoping replaces per-request project IDs
X-Merge-TagsDrop. No per-request tags; attribution comes from the key/team/org
Merge optionConcentrate replacement
merge-gateway-sdk (MergeGateway)OpenAI SDK pointed at https://api.concentrate.ai/v1
merge-gateway-ai-sdk-provider (createMergeGateway)@ai-sdk/openai createOpenAI with baseURL set to Concentrate
providerOptions.mergeGateway (tags, vendor routing, routing metadata)Drop. Vendor routing → model slug (provider/model-id) or routing.*; tags / metadata → key/team/org rollups
requestOptions.extraBodyProperties (used to send project_id in the body)Drop. No per-request project field
extra_headers={"X-Project-Id": ...} (Python)Drop. Per-key / team / org scoping
Merge response headerConcentrate equivalent
Merge request / trace idX-Request-Id (Concentrate returns its own per-request id, surfaced in dashboard logs)
Resolved-provider / routing-decision headersNo header. The resolved provider is recorded per request in the dashboard
Rate-limit headersStandard X-RateLimit-* headers. See Errors for 429 semantics

Step 4: Decompose Your Routing Policy

Merge bundles routing into named routing policies (referenced by routing_policy_id, or handed off via model: "default_routing"). Concentrate has no routing-policy primitive. Each behavior is either on by default or expressed as a body param on the request. Expand the table below for the full mapping.
Merge routing strategyConcentrate equivalent
Single (type: "fallback", one target)Pin the model: model: "provider/model-id"
Priority (type: "fallback", ordered targets)routing.model.fallbacks / routing.provider.fallbacks (ordered)
Least Latencymodel: "auto" with routing.model.sort: "latency"
Lowest Costmodel: "auto" with routing.model.sort: "cost"
Cost Optimized (type: "intelligent", axis: "cost")model: "auto" with routing.model.sort: "cost"
Balanced (type: "intelligent", axis: "performance")model: "auto" with routing.model.sort: "performance" (default)
Quality First (type: "intelligent", axis: "intelligence")model: "auto" with routing.model.sort: "performance"
Merge’s tag-based routing (rules with operators eq, gt, in, contains, starts_with, exists and AND/OR logic that steer a request by its tags) has no direct equivalent. Concentrate’s conditional routing conditions on request capabilities (feature support, ZDR flag, per-feature uptime, cache affinity), not on request attributes like tags. If your policy routes on tags, the migration path is to issue separate keys per condition and pick the key in application code.

Step 5: Update Model Identifiers

Concentrate accepts model strings in two forms:
  • Bare slug, e.g. gpt-4o, claude-haiku-4-5, auto. Routing picks a provider.
  • provider/model-id, e.g. bedrock/claude-haiku-4-5, openai/gpt-4o. Pins the request to a specific provider.
Merge already uses provider-prefixed slugs in its native SDK (openai/gpt-4o, anthropic/claude-sonnet-4-20250514), so most strings carry over directly. The SDK shims (OpenAI, Anthropic) used bare slugs, which work as-is too. One thing to know about the slashed form: the prefix is the provider that serves the request, not the model’s author. For most popular names the two are the same string (openai, anthropic, mistral, cohere). They diverge whenever a model is hosted by something other than its author:
AuthorProvider serving the requestConcentrate slug
Anthropic (claude-haiku-4-5)Anthropicanthropic/claude-haiku-4-5
Anthropic (same model, different host)AWS Bedrockbedrock/claude-haiku-4-5
Anthropic (same model, different host)Azureazure/claude-haiku-4-5
Google (gemini-3.5-flash)Google AI Studioai-studio/gemini-3.5-flash
Meta (llama-3-8b-instruct)AWS Bedrockbedrock/llama-3-8b-instruct
Bare slugs work in all of these cases. Use them when you don’t care which provider serves the request. Use the provider/ prefix when you specifically want to pin to one host (for ZDR compliance, contractual reasons, or latency in a specific region). The only universally required slug change is auto-routing:
Merge GatewayConcentrate AI
model: "default_routing" (or omit model)model: "auto" with explicit routing.model.sort (cost / latency / performance)
For the authoritative list of supported provider/model-id pairs, call GET /v1/models or browse the Model Fortress.

Step 6: Map Projects, Budgets, and Compression

Merge’s project, budget, and compression features map onto Concentrate’s key hierarchy and built-in routing rather than per-request configuration.
Merge Gateway conceptConcentrate equivalent
Project (slug-based org unit with its own budget, routing policy, and compression)Team or a dedicated key within an organization. Spend, routing, and limits attach to the key/team
Budget: Soft Limit (alerts only; thresholds 50 / 80 / 90%)Spend alerts on the key/team
Budget: Hard Limit (HTTP 402 block)Per-key spend limits; requests are rejected once the cap is hit
Budget periods (daily / weekly / monthly / quarterly / yearly)Per-key spend limits in the dashboard
Context compression (Context Window Only / Cost Optimization / Disabled; lossless JSON minification + middle-message trimming)No gateway-side compression. Manage context in application code, or rely on auto-routing to pick a model with sufficient context
BYOK ($0.05 / M tokens)Not applicable. Concentrate owns provider credentials at no per-token BYOK fee

Step 7: Reconnect Observability

Concentrate’s dashboard covers the major surfaces you used in the Merge Gateway dashboard (gateway.merge.dev).
Merge Gateway surfaceConcentrate equivalent
Request logs (every routing decision, cost, outcome)Per-request logs at concentrate.ai
Project-scoped spendOrg / team / developer / key spend rollups
Tag breakdownsPer-key / team / org rollups. No per-request tag dimension
Routing decision historyResolved provider recorded per request in the dashboard
Budgets & spend capsPer-key rate and spend limits
Audit trail / roles & permissionsOrganization and team members + audit logs in the dashboard
Security (blocklist, geo routing, prompt injection, DLP)Guardrails & Redaction; per-key Zero Data Retention

Exporting your Merge history

Merge Gateway’s dashboards do not import into Concentrate, and the reverse is also true. Historical request logs stay where they were created. If your migration is driven by compliance or audit requirements, export your history from the Merge Gateway dashboard before deprovisioning.

Step 8 (Optional): Adopt the Responses API

If you used Merge’s native merge-gateway-sdk, you were already on a Responses-style API. Concentrate’s native Responses API is the direct successor: it supports streaming, tool calling, structured output, multi-modal input, and web search through a single normalized shape across every provider, and previous_response_id links related requests into a server-managed conversation tree.
curl https://api.concentrate.ai/v1/responses \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $CONCENTRATE_API_KEY" \
  -d '{
    "model": "anthropic/claude-opus-4-6",
    "input": "What is the capital of France?"
  }'

Why migrate to Concentrate

Merge Gateway exposes one native endpoint plus four SDK-compatibility shims, each on its own base URL. Migrating collapses all five onto Concentrate’s single base URL https://api.concentrate.ai/v1.
Merge integrationMerge base URL
Native Merge Gateway SDKhttps://api-gateway.merge.dev/v1
OpenAI SDKhttps://api-gateway.merge.dev/v1/openai
Anthropic SDKhttps://api-gateway.merge.dev/v1/anthropic
Vercel AI SDKhttps://api-gateway.merge.dev/v1/ai-sdk
LangChainhttps://api-gateway.merge.dev/v1/openai
The native merge-gateway-sdk is Responses-style (client.responses.create(...)). Its closest one-to-one target is Concentrate’s Responses API, reachable from the standard OpenAI SDK or any HTTP client.
Concentrate organizes billing around an organization → team → developer → key hierarchy. Set budgets at any level and roll spend up into a single dashboard. Per-team budgets and per-developer attribution come from the key itself, so there’s no per-request project_id tagging to maintain.
Beyond ordered model and provider fallbacks (routing.model.fallbacks, routing.provider.fallbacks), Concentrate’s routing layer ships:
  • Uptime gate. Providers whose per-feature success rate drops below 90% are skipped.
  • Feature degradation. If no provider supports the full requested feature set (e.g. json_schema), the request is downgraded to json_object or text instead of failing.
  • Cache-affinity routing. When multiple providers can serve a request, the one where your actor already has cached tokens is preferred.
All on by default. No routing policy to author, name, or version.
model: "auto" accepts an explicit optimization target via routing.model.sort: cost, latency, or performance (default). See Auto Routing. This maps cleanly onto Merge’s intelligent routing axes (cost / performance / intelligence).
Like Merge Gateway’s native SDK, Concentrate exposes a first-class Responses API. Alongside it you also get OpenAI Chat Completions compatibility and an Anthropic-compatible Messages API.
Concentrate is BYOK-free. Point at a model and Concentrate owns the upstream credentials. Any provider keys you carried for Merge’s BYOK mode can be retired after migrating, with no per-token BYOK fee.

Troubleshooting

Bare slugs (gpt-4o, claude-haiku-4-5) and provider/model-id slugs both work. If you’re using a provider/ prefix and getting a miss, double-check the prefix is a provider (e.g. bedrock, azure, ai-studio) and not just the author (e.g. meta, google). Call GET /v1/models for the authoritative list.
Concentrate keys start with sk-cn-v1-. If you are still sending a Merge mg_... key as the Authorization bearer, you will see a 401. Verify the value in your dashboard and confirm there are no extra spaces or quotes.
Confirm the base URL is https://api.concentrate.ai/v1, not api-gateway.merge.dev. If the SDK is still pointed at Merge it is logging against your Merge Gateway dashboard, not Concentrate.
Concentrate has no project_id body field or X-Project-Id header. Per-project spend and analytics come from issuing a separate key (or team) per project; rollups happen automatically by key/team/org. Drop both the project_id body field and the X-Project-Id header.
routing_policy_id and model: "default_routing" are no-ops on Concentrate. Express fallbacks via routing.model.fallbacks / routing.provider.fallbacks body params, or use model: "auto" with a routing strategy. Tag-based routing has no direct equivalent, so handle it with per-condition keys in application code.
Confirm the base URL is https://api.concentrate.ai/v1 (no /api segment, no per-SDK suffix like /openai or /anthropic). Test the connection manually:
curl https://api.concentrate.ai/v1/responses/health

Next Steps

API Reference

Explore the full API capabilities

Available Models

Browse all supported models

Auto Routing

Optimize model selection automatically

Get Support

Contact our support team

Feedback

If you hit anything that didn’t translate cleanly (especially around projects, routing policies, tag-based routing, context compression, or per-request scoping), email support@concentrate.ai. The capability gaps called out above are tracked, and migration friction reports directly shape what we ship next.