Get started
Paste one of these into your coding agent and it works with you to set things up: wire an OpenAI client to the gateway, wire your coding agent to it, or switch from OpenRouter in one paste. Each prompt is first-person, so pasting it is your instruction and consent.
Copy a prompt below and paste it into a CLI coding agent (Claude Code, Codex, and the like). The agent follows it end to end. The prompts are the same ones the in-app onboarding uses, and they carry this deployment's URLs (web https://pr-2007.preview.experientiallabs.ai, API https://api-pr-2007.preview.experientiallabs.ai).
Signed out? Paste this into a CLI agent to create your account instantly from your email, wire the gateway, and confirm the key.
1. Ask me for my email address. Ask medirectly ("What's your email? I'll create your Experiential Labs accountwith it.") and wait for my answer. Use exactly the address I give you.Never invent or guess an address, and never go looking for one in myfiles, git config, or shell history. Call the result MY_EMAIL.Show me the Terms (https://platform.experientiallabs.ai/terms) and Privacy (https://platform.experientiallabs.ai/privacy)links and ask whether I agree to the terms and privacy conditions.Wait for my affirmative answer before creating an account. Do not infer agreement.2. Create my account instantly, no browser, no password, no code.POST https://pr-2007.preview.experientiallabs.ai/api/signup/instant (no auth)Header: Content-Type: application/jsonBody: {"email": "<MY_EMAIL>", "agree": true}On 200 capture: api_key (an xpl_ key, this is mine, keep it secret), org_id,credits_granted, verification_required, overview_url. Handle the others:- 409 account_exists -> I already have an account; stop and tell me tosign in at https://pr-2007.preview.experientiallabs.ai/signin to get a key (don't retry with another email).- 403 signup_disabled | signup_domain_blocked | work_email | signup_refused-> the signup was refused; show me the response's`error` text verbatim (it says what to do) and stop.- 428 terms_acceptance_required -> show the policy links and ask for agreement.- 429 rate_limited -> too many signups from here; wait, then retry once.- 400 invalid_request -> the email was rejected; ask me for a valid one.Store the api_key as EXPLABS_API_KEY in my env; never print the full key morethan once.3. Wire an OpenAI client to the gateway.base_url = "https://api-pr-2007.preview.experientiallabs.ai/v1"api_key = EXPLABS_API_KEY (the xpl_ key from step 2). One header only:Authorization: Bearer <api_key>.4. Confirm the key is live, this does NOT spend credits.GET https://api-pr-2007.preview.experientiallabs.ai/v1/models with the key -> the models my account can call. Do NOTmake a paid chat completion yet: follow the activation steps shown atoverview_url first. If payment is required, I complete it myself onhttps://pr-2007.preview.experientiallabs.ai/credits. If manual review is required, help me submit an appeal andwait for approval; payment cannot unlock that review. Landing my traces astelemetry works regardless.
Paste into your agent: it asks where to wire the gateway and which model to test, with a recommendation, then makes one call.
I'm setting up Experiential Labs as this project's model gateway. I pasted thismyself, treat it as my instructions and my consent. I'm already signed in; my keyis below. Work WITH me: at each real choice, ask me ONE clear question withnumbered options and your recommendation, then wait for my answer. Don't guess.My gateway API key (a secret: put it in env, never commit it, never echo it inlogs):EXPLABS_API_KEY=<paste my org API key from https://pr-2007.preview.experientiallabs.ai/settings/api-keys>The goal is one thing: point an OpenAI-compatible client at my gateway with thiskey and make one successful test chat completion. Print what you do at each step.1. Ask me where to wire it (options + your recommendation), then wait. Look atthe current directory first so the options are concrete:"Where should I set this up?(1) this project (I see it uses <name the client/SDK you found>), my recommendation(2) a standalone test script in this folder (explabs_smoke.py / .mjs)(3) somewhere else, tell me whereWhich one?"For (1): set base_url = https://api-pr-2007.preview.experientiallabs.ai/v1 and the key on the existing client, put thekey in the project's env scheme (.env plus an example entry), never in code,and show me the change first. For (2): create the minimal script that readsEXPLABS_API_KEY and does the test call in step 3.2. Ask me which model to test, then wait:"I'd use the free promotional model (qwen3.8-27b at launch) so this test costsnothing. Use that, or name another? GET https://api-pr-2007.preview.experientiallabs.ai/v1/models lists what my keycan call; use the ids EXACTLY as returned."3. Make the test call with the model I chose. Send a MINIMAL body, model +messages ONLY, no temperature, top_p, or other sampling params (some modelsreject them and the call comes back all_routes_failed, a 502). One header:Authorization: Bearer $EXPLABS_API_KEY. This runs on the platform-fundedlane, a fraction of a cent of my free credits, and proves serving and billingend to end. Do NOT use any of my own provider keys for this test.4. Report back what you changed and the test call (the model, that it succeeded,and its cost). Then ask me which optional follow-ups I want, with yourrecommendation, and do only the ones I pick:(a) Connect my own provider keys (BYOK, Pro) so those calls bill my own accounts(b) Import my Claude Code / Codex usage history (metadata only)(c) Review my credits and spendBYOK and import are quick for me to do at https://pr-2007.preview.experientiallabs.ai/settings; balances live athttps://pr-2007.preview.experientiallabs.ai/credits.Read the contract if you build further: https://pr-2007.preview.experientiallabs.ai/docs (human docs) andhttps://pr-2007.preview.experientiallabs.ai/llms.txt (machine-readable: honored and refused parameters, error codes,streaming caveats). Follow it literally.
Paste into Claude Code, Codex, OpenCode, Hermes Agent, Pi, Cline, VS Code Copilot, Conductor, Cursor, or any OpenAI-SDK tool: the agent identifies itself and applies its own verified integration.
I pasted this into you myself, wire THIS coding agent up to my ExperientialLabs gateway, so my model calls route through https://api-pr-2007.preview.experientiallabs.ai and show up in my usage.Ground rules: never print my full key (first 8 characters at most), ask mebefore you edit any config file or shell profile, and if you cannot do a step(no file access, settings live in a GUI), print the exact manual steps for meinstead. Print what you're doing at each step.1. Get my key. Use EXPLABS_API_KEY from my environment if it is set; otherwiseask me to paste one (I can mint it at https://pr-2007.preview.experientiallabs.ai/settings/api-keys). It lookslike xpl_ followed by 40 hex characters.2. Prove the key works before touching any config:GET https://api-pr-2007.preview.experientiallabs.ai/v1/models with header "Authorization: Bearer <key>" -> 200 andthe model slugs I can call. Remember the list; I'll pick models from it.3. Identify which agent you are and apply YOUR integration:- Claude Code:You cannot repoint yourself mid-session, and switching auth under a runningsession causes mixed-state errors. First prove the lane without touching anyconfig, via one isolated subprocess run from this project (so my MCP serversand plugins load and their tool schemas ride the request. Tool schemas arewhere provider strictness bites, so a bare hello proves too little):ANTHROPIC_BASE_URL="https://api-pr-2007.preview.experientiallabs.ai" ANTHROPIC_API_KEY="<my key>" \ANTHROPIC_MODEL="<slug I pick>" \claude -p "list your available tools, then read ./README.md and replywith its first heading"Pass only if that run completes with tools listed and a real tool use.Then offer me two placements and apply the one I pick:(a) append to my shell profile, or (b) print for one-off use:export ANTHROPIC_BASE_URL="https://api-pr-2007.preview.experientiallabs.ai" # no /v1 suffixexport ANTHROPIC_API_KEY="<my key>"export ANTHROPIC_MODEL="<slug I pick>"Use ANTHROPIC_API_KEY, never ANTHROPIC_AUTH_TOKEN: an existing claude.aisign-in can outrank AUTH_TOKEN and send the gateway an OAuth token instead.Then tell me to start a NEW session from a shell with those set. Name themodel by its gateway slug exactly as GET https://api-pr-2007.preview.experientiallabs.ai/v1/models lists it (the DOTform, e.g. claude-fable-5.1 — Anthropic's dashed ids like claude-fable-5-1answer 403 model_not_granted). If the slug is not an Anthropic model, alsoexport CLAUDE_CODE_MAX_CONTEXT_TOKENS=<max_input_tokens fromGET https://api-pr-2007.preview.experientiallabs.ai/api/models/<slug>, rounded down to the nearest 50k> — Claude Codeassumes 200k for names it does not know and compacts early. NEVER usecontext_window for that pin: on an OpenAI-family model it is a total windowthe provider counts the model's maximum output inside, so a session pinned toit never compacts before the provider refuses it and /compact then fails thesame way. max_input_tokens already accounts for this per maker, so it isalways the right pin. Warn me plainly: if a session ever shows"Not logged in · Please run /login", do NOT run /login (it starts AnthropicOAuth that overrides the gateway) — restart with --resume, and if itpersists, my <config dir>/.claude.json remembers a "No" to the custom-API-keyprompt under customApiKeyResponses.rejected: answer Yes or move the entry toapproved. Images work on image-capable routes and are rejected by name ontext-only ones; extended thinking passes through on all-Anthropic routesand is translated to reasoning effort elsewhere.- Conductor:Conductor launches Claude Code with the environment it captured from mylogin shell (interactive login shell, cached per workspace) merged with itsown settings, and passes the per-chat picker choice as --model — so themodel is routed by remapping picker aliases with ANTHROPIC_DEFAULT_*_MODELvariables (ANTHROPIC_MODEL does not apply to picker selections). Offer metwo placements and apply the one I pick:(a) per-repo, recommended: merge into this repo's .claude/settings.json"env" block (committed; Claude Code applies it in every workspace, and itoverrides anything Conductor captured from my shell), oneANTHROPIC_DEFAULT_<ALIAS>_MODEL entry per picker alias I use:{ "env": { "ANTHROPIC_BASE_URL": "https://api-pr-2007.preview.experientiallabs.ai","ANTHROPIC_DEFAULT_OPUS_MODEL": "<slug I pick>" } }then put ONLY the key machine-local in .conductor/settings.local.tomlunder [environment_variables] (make sure that file isgit-ignored before writing my key into it):ANTHROPIC_API_KEY = "<my key>"(b) app-wide: print the same variables for me to add by hand inConductor -> Settings -> Environment, and remind me to check thatSettings -> Harnesses -> Claude Code uses my API key, not a claude.aiCLI login.Warn me either way: settings reach newly created workspaces, not runningones, and if my shell profile exports a direct AnthropicANTHROPIC_API_KEY, Conductor's capture hands it to every agent —placement (a) overrides it; otherwise I should remove the export.The key rides ANTHROPIC_API_KEY, never ANTHROPIC_AUTH_TOKEN: an existingclaude.ai sign-in can outrank AUTH_TOKEN, and a set API key also stopsClaude Code from trying to authenticate with Anthropic directly.- OpenAI Codex CLI:First prove the lane in a throwaway home so my real ~/.codex (config,sessions, auth) stays untouched, and test with my REAL tool surface: yousend every mcp_servers/plugin tool schema on each request, and tool schemasare where provider strictness bites, so a bare hello proves too little.Copy ~/.codex into a fresh "$(mktemp -d)", append ONLY the[model_providers.explabs] table below to that copy's config.toml, then runCODEX_HOME=<that dir> codex exec -m "<slug I pick>" \-c model_provider=explabs -c model_reasoning_effort=max \"list your available tools, then read ./README.md and reply with itsfirst heading"Pass only if it completes with my MCP/plugin tools listed and a real tooluse. Then add the whole block to ~/.codex/config.toml (create it ifmissing, show me the diff before writing) and tell me to start a new Codexsession:model = "<slug I pick>"model_provider = "explabs"model_reasoning_effort = "max" # reasoning models; "max" is the top tier[model_providers.explabs]name = "Experiential Labs"base_url = "https://api-pr-2007.preview.experientiallabs.ai/v1"env_key = "EXPLABS_API_KEY"wire_api = "responses"Leave requires_openai_auth unset, and make sure EXPLABS_API_KEY is exportedwhere I launch you (export KEY=..., a plain KEY=... line is invisible tochild processes like me).- OpenCode:Write the provider block into this project's opencode.json (or~/.config/opencode/opencode.json if I prefer global, ask):{"provider": {"explabs": {"npm": "@ai-sdk/openai-compatible","name": "Experiential Labs","options": {"baseURL": "https://api-pr-2007.preview.experientiallabs.ai/v1", "apiKey": "{env:EXPLABS_API_KEY}"},"models": {"<slug>": {"name": "<slug>"}}}}Fill limit.context/limit.output and cost ({"input": $/1M, "output": $/1M},i.e. the catalog's *_nano_usd_per_million / 1000000000) for each slug fromGET https://api-pr-2007.preview.experientiallabs.ai/api/models/<slug> so my context window and spend display are right.- Hermes Agent (Nous Research):First prove the lane in a throwaway data dir so my real ~/.hermes (config,sessions, memories) stays untouched: create "$(mktemp -d)", write ONLY theconfig below plus a .env line EXPLABS_API_KEY=<my key> (chmod 600) into it,then runHERMES_HOME=<that dir> hermes -z "list your available tools, then read./README.md and reply with its first heading"Pass only if that run completes with tools listed and a real toolround-trip. Then merge the same block into ~/.hermes/config.yaml (show methe diff before writing) and put the key line in ~/.hermes/.env:providers:explabs:base_url: "https://api-pr-2007.preview.experientiallabs.ai/v1"key_env: "EXPLABS_API_KEY"api_mode: chat_completionsmodel:provider: "custom:explabs"default: "<slug I pick>"Any catalog slug works as the default, and /model custom:explabs:<slug>switches mid-session. Warn me plainly: Hermes' session-title side callsends a temperature value, so on models that pin their sampling the titlefalls back to a default — the session itself is unaffected.- Pi:First prove the lane in a throwaway home so my real ~/.pi (auth, sessions,model store) stays untouched: pi resolves its agent dir from HOME, so create"$(mktemp -d)" and copy my real ~/.pi into it (extensions, skills, andsettings ride the test — tool schemas are where provider strictness bites,so a defaults-only run proves too little; if ~/.pi does not exist yet, justcreate <that dir>/.pi/agent). Then merge the block below into that copy's.pi/agent/models.json and runHOME=<that dir> EXPLABS_API_KEY=<my key> pi -p --provider explabs \--model "<slug I pick>" "list your available tools, then read./README.md and reply with its first heading"Pass only if that run completes with tools listed and a real toolround-trip, then DELETE the throwaway home ("rm -rf <that dir>") — the copycarries my auth and session state and must not outlive the proof. Thenmerge the same provider into ~/.pi/agent/models.json(create it as {"providers": {}} if missing; show me the diff beforewriting):{ "providers": { "explabs": {"baseUrl": "https://api-pr-2007.preview.experientiallabs.ai/v1","api": "openai-completions","apiKey": "$EXPLABS_API_KEY","models": [ { "id": "<slug I pick>", "name": "<slug I pick>","reasoning": true, "input": ["text", "image"],"contextWindow": <from GET https://api-pr-2007.preview.experientiallabs.ai/api/models/<slug>>,"maxTokens": <from the same> } ] } } }The apiKey stays the literal string "$EXPLABS_API_KEY" — pi interpolates itfrom my environment, so make sure the variable is exported where I launchpi and never write the raw key into the file. Set reasoning/input to theslug's actual catalog capabilities. Any catalog slug works; I pick modelswith --model at launch or /model in-session (models.json reloads each time/model opens, no restart).- Cline:Your settings live in the VS Code UI, so print these for me to set by hand:API Provider "OpenAI Compatible"; Base URL https://api-pr-2007.preview.experientiallabs.ai/v1; API Key = my key (noBearer prefix); Model ID = a slug from step 2; and per-model context window /max output tokens from https://api-pr-2007.preview.experientiallabs.ai/api/models/<slug>.- VS Code (Copilot Chat):Copilot's bring-your-own-model support is VS Code core (1.122+); chat andagent mode need no Copilot plan. Find my VS Code user dir (macOS~/Library/Application Support/Code/User, Linux ~/.config/Code/User, Windows%APPDATA%\Code\User) and merge this entry into chatLanguageModels.jsonthere (create the file as a JSON array if missing), one models[] item perslug I pick:{ "name": "Experiential Labs", "vendor": "customendpoint","apiType": "chat-completions","models": [ { "id": "<slug I pick>", "name": "<slug I pick>","url": "https://api-pr-2007.preview.experientiallabs.ai/v1/chat/completions","toolCalling": true, "vision": true,"modelOptions": { "temperature": null, "top_p": null } } ] }Set toolCalling and vision to each slug's ACTUAL capabilities fromGET https://api-pr-2007.preview.experientiallabs.ai/api/models/<slug> (tool support and image input) — declaring acapability the model lacks makes Copilot send tool calls or images theroute rejects.The null modelOptions are required, not decoration: null deletes the field,and Copilot otherwise sends temperature 0.1 and top_p 1 on every request,which models that pin their sampling reject with a 400 naming theparameter. You cannot enter my key — it lives in VS Code's encrypted secretstorage — so print the manual step: in the Chat model picker open ManageModels, right-click the Experiential Labs model, choose to enter an APIkey, and paste my key (<my key>). VS Code stores it encrypted and writesthe ${input:chat.lm.secret.*} references into the entry itself; neverhand-write a raw key into the file.- Cursor:Your gateway settings live in the Cursor Settings UI, so print these for meto set by hand. First tell me the prerequisite: a paid Cursor plan (the Freeplan serves only Auto and refuses named models, which custom models are).Then: in Cursor Settings -> Models -> API Keys, put my key in"OpenAI API Key" (no Bearer prefix), enable "Override OpenAI Base URL" andset it to https://api-pr-2007.preview.experientiallabs.ai/v1. Add each slug I pick as a custom modelname in the models list; custom models ride the override in OpenAI format,so any catalog slug works. Warn me plainly: Cursor relays requests throughits own servers, Tab autocomplete stays on Cursor's models, and if a chatanswers 400 invalid_parameter naming temperature or top_p, that model pinsits sampling (the Claude 5 family pins temperature to 1). Pick adifferent slug.- Any other OpenAI-compatible tool:Export OPENAI_BASE_URL="https://api-pr-2007.preview.experientiallabs.ai/v1" and OPENAI_API_KEY="<my key>" wherever Ilaunch you, and name models by slug. If your own config wants the valuesinstead, it needs the same three: base URL https://api-pr-2007.preview.experientiallabs.ai/v1, my key, and a slug.4. Verify end to end. Make one tiny completion with the surface you configured("reply with the single word: ok", small max output), via your own nextmodel call if you now route through the gateway, otherwise via curl with mykey. Then tell me it landed and that I can watch every call athttps://pr-2007.preview.experientiallabs.ai/telemetry.5. Recap exactly what you changed (files and values, key shown as xpl_ prefixonly) so I can undo it later.
Org admins: paste into your agent with a provisioning key and it creates your identities (coding, product, ...) with one inference key each, so spend buckets per identity.
Set up per-identity API keys for my Experiential Labs organization sospend is bucketed per identity (for example "coding" vs "product") in usage.Provisioning key: xpl_<paste-your-provisioning-key-here>(I replace the placeholder above before sending. It is a PROVISIONING key:it can manage this org's keys, identities, and budgets. Never print it backto me, never write it into any file, and do not use it for inference. TheAPI does not stop you from doing those; these are my rules.)Base URLs: API https://api-pr-2007.preview.experientiallabs.ai (management under /api, inference under /v1),dashboard https://pr-2007.preview.experientiallabs.ai. Every call below sendsAuthorization: Bearer <the provisioning key>plus Content-Type: application/json on writes. On a non-2xx read the JSON"error" field; a body with "detail" instead is a request-shape failure anddetail[0].loc[-1] names the offending field. Then apply the Fallbacks.What this key can call: GET /api/whoami; GET, POST /api/orgs/{org_id}/identities; PATCH /api/orgs/{org_id}/identities/{identity_id} (display_name and description only); GET, POST /api/v1/keys; GET, PATCH, DELETE /api/v1/keys/{hash}; GET, PUT /api/orgs/{org_id}/budgets; DELETE /api/orgs/{org_id}/budgets/{budget_id} (identity- and key-scope budgets this key created); GET /api/orgs/{org_id}/usage/by-identity.Disabling an identity, model grants, org-wide budgets, the default identity'sbudget, and any budget an admin set are the admin's, on https://pr-2007.preview.experientiallabs.ai/api-keys; if astep needs one of those, ask me instead.1. Discover the organization (reads only).GET https://api-pr-2007.preview.experientiallabs.ai/api/whoami -> {org_id, org_slug, org_name}. Keep org_id; every/api/orgs/{org_id}/... call below uses it. ThenGET https://api-pr-2007.preview.experientiallabs.ai/api/orgs/{org_id}/identities -> {identities: [{identity_id,display_name, active, is_default, ...}]}. The is_default row is the org'sown identity: leave it alone, mint no keys under it, cap nothing on it.2. Intake, BEFORE any change. Do not send a single POST, PUT, PATCH, orDELETE until I have answered these and said yes to the plan. Ask me, inmy words, skipping any question my message already answers:- What identities do I want? Identities are spend buckets, usually one perteam, product, or agent. Ask: "Do you have more than one product?Which teams or agents will call the API?" Offer these as a startingpoint, and take my renames, drops, and additions:coding - IDE and terminal coding agentsproduct - the product's own inference trafficresearch - experiments, evals, notebooks- Does each identity need its own inference key, and which tool orservice will hold it (Claude Code, Codex, a server, ...)? One key peridentity is the default; say so and let me change it.- Do I want a spend budget per identity? If yes: how much (USD) and forwhat period, monthly recurring or one calendar month, on the identityor on its key. If I have no number, propose none: no budget means no cap.Then show me the plan as ONE table: identity_id, display name, purpose,key name and the tool it goes to (or "no key"), budget (amount + period,or "none"). Wait for my explicit "yes". Anything else is an edit: apply itand show the table again. The first write happens only after that yes.3. Create each identity (reuse one that exists).POST https://api-pr-2007.preview.experientiallabs.ai/api/orgs/{org_id}/identities{"display_name": "Coding", "identity_id": "coding", "description": "<one line>"}201 -> created. 409 (code identity_id_unavailable) -> the id alreadyexists: if it is in MY list from step 1, reuse that identity; otherwise(ids are unique platform-wide, and only need to be unique to my tooling)retry ONCE with details.suggested_id from that response. identity_idstarts with a letter, continues with lowercase letters or digits, groupsjoined by ".", "-" or "_", and never starts with "org-". If step 1 listedthe identity with active=false, do not use it: an admin disabled it onpurpose and only the dashboard re-enables it. Tell me and pick another.4. Mint the inference keys the plan names (one per identity by default).POST https://api-pr-2007.preview.experientiallabs.ai/api/v1/keys{"name": "<identity>-<tool>", "identity_id": "<identity_id>"}200 -> {data: {hash, name, identity_id, ...}, key: "xpl_..."}. The plaintextappears exactly once; hold it only until step 6. Never set "provisioning":true on these keys (the API would allow it; I do not). Checkdata.identity_id matches. An optional DAILY USD cap: "limit": 5 in the body.5. Budgets, only where the plan has one, in nano-USD ($1 = 1000000000)."period": "*" recurs every month; "period": "YYYY-MM" caps that onecalendar month only. 0 is a HARD $0 cap, never "no cap"; remove one withDELETE https://api-pr-2007.preview.experientiallabs.ai/api/orgs/{org_id}/budgets/{budget_id}. Replace or delete onlybudgets this key created (an admin's row is 403). Never the default identity's.PUT https://api-pr-2007.preview.experientiallabs.ai/api/orgs/{org_id}/budgets{"period": "*", "scope_kind": "identity", "identity_id": "coding","limit_nano_usd": 50000000000} # $50 every month for the identity{"period": "*", "scope_kind": "key", "api_key_id": "<data.hash>","limit_nano_usd": 20000000000} # $20 every month for one key{"period": "2026-10", "scope_kind": "identity", "identity_id": "coding","limit_nano_usd": 5000000000} # $5 for October 2026 onlyOnly those two scope kinds are this key's to set. Read back withthe calendar month, never "*": GET https://api-pr-2007.preview.experientiallabs.ai/api/orgs/{org_id}/budgets?period=YYYY-MM6. Hand me one table: identity -> key name -> where the key goes. Print eachnew key exactly once, in that table, and nowhere else. Never commit a key;prefer the OS keychain or a .env file that is gitignored. Per tool:Claude Code: export ANTHROPIC_BASE_URL="https://api-pr-2007.preview.experientiallabs.ai" (no /v1 suffix)export ANTHROPIC_API_KEY="<key>"export ANTHROPIC_MODEL="<slug from GET https://api-pr-2007.preview.experientiallabs.ai/v1/models>"Codex, Cline, Cursor, the OpenAI SDK, any OpenAI-compatible tool:export OPENAI_BASE_URL="https://api-pr-2007.preview.experientiallabs.ai/v1"export OPENAI_API_KEY="<key>"OpenCode: a provider in opencode.json with"npm": "@ai-sdk/openai-compatible" and"options": {"baseURL": "https://api-pr-2007.preview.experientiallabs.ai/v1", "apiKey": "{env:OPENAI_API_KEY}"}A server: the same OPENAI_* pair in its secret store. Per-toolsteps: https://pr-2007.preview.experientiallabs.ai/docs/coding-agents.7. Verify every key with one request and show me where the spend lands.GET https://api-pr-2007.preview.experientiallabs.ai/v1/models (bearer required) for a slug, thenPOST https://api-pr-2007.preview.experientiallabs.ai/v1/chat/completions with Authorization: Bearer <that key>{"model": "<slug>", "max_tokens": 5,"messages": [{"role": "user", "content": "ping"}]}Then, with the provisioning key,GET https://api-pr-2007.preview.experientiallabs.ai/api/orgs/{org_id}/usage/by-identity?window=30d and confirm eachidentity row lists its key with a request_count (only keys that carriedtraffic appear; a deleted key's traffic is the identity_id null row; keysminted without a group fold under the Default row). https://pr-2007.preview.experientiallabs.ai/api-keys showsper-key spend.Fallbacks:- 401 on a route in the list above: the key is wrong or revoked; ask me tocheck the paste. 401 on a route NOT in that list is the edge refusing it toevery key, not a key problem: hand that step to me.- 403 "A provisioning key is required": my key is an inference key. Stop andtell me to mint a provisioning key as an org admin on https://pr-2007.preview.experientiallabs.ai/api-keys(Create key -> Configuration -> Provisioning key). Any other 403 names whatthis key may not do: hand that step to me.- 404 on an identity or budget path: that id does not exist in this org;re-list and check the id. 404 on /api/orgs/{org_id} itself: org_id is notthis key's org; re-read it from https://api-pr-2007.preview.experientiallabs.ai/api/whoami.- 409 on an identity: in my step-1 list -> reuse it; otherwise retry oncewith details.suggested_id. 409 on a key mint: that identity is disabled;tell me and use another one. Never try to re-enable it.- 422 with "error": the message names the rule (identity_id shape, scopekinds, period). 422 with "detail": detail[0].loc[-1] names the field (amissing display_name, a non-numeric limit, a budgets read without period).A NEGATIVE key limit is a 400 with "error" instead; nothing is minted.- 429, or 503 "gateway is updating": wait Retry-After seconds (30 if absent)and retry that call once. A key mint is not idempotent: listGET https://api-pr-2007.preview.experientiallabs.ai/api/v1/keys before minting again so no identity gets two keys.- 500 internal_error "cannot serve this request natively" on the verifyrequest: no serviceable lane for that model here. Try one other slug fromGET https://api-pr-2007.preview.experientiallabs.ai/v1/models; if that fails the same way, stop and report it.- Never print the provisioning key, store a key in the repo, or paste keyswhere I did not ask for them.
Paste into your coding agent: it finds the existing integration, moves the base URL and key, maps model ids against the live catalog, moves cost reads onto the Cost API, and verifies with one call.
I'm replacing my current model provider or gateway with Experiential Labs asthis project's model gateway. I pasted this myself: treat it as my instructionsand my consent. Work WITH me: at each real choice, ask me ONE clear questionwith numbered options and your recommendation, then wait. Don't guess. Printwhat you do at each step, and never print my full API key (first 8 charactersat most). Read the full machine-readable contract first: https://pr-2007.preview.experientiallabs.ai/llms.txt (baseURLs, every route, honored and refused parameters, cost fields, error codes).Follow it literally.1. Find the current integration. Search this project for the provider's baseURL, its key variable, its SDK/client construction, hardcoded model ids,provider-specific request fields (provider preferences, transforms,fallback model lists, referer/title headers), and any code that reads costor usage from it. Show me the list of files and call sites before changinganything.2. Get my Experiential key. Ask me: "Do you have an xpl_ key already?(1) yes, I'll paste it(2) no, create my account"For (2): ask me for my email (never scavenge one from my files or gitconfig), show me https://pr-2007.preview.experientiallabs.ai/terms and https://pr-2007.preview.experientiallabs.ai/privacy and wait for myagreement, thenPOST https://pr-2007.preview.experientiallabs.ai/api/signup/instant (no auth)Header: Content-Type: application/jsonBody: {"email": "<MY_EMAIL>", "agree": true}On 200 capture api_key. On 409 account_exists tell me to sign in athttps://pr-2007.preview.experientiallabs.ai/signin for a key and stop. On any other error show me the response's`error` text verbatim and stop.Store the key as EXPLABS_API_KEY in my env scheme (.env plus an exampleentry), never in code.3. Switch the base URL. The gateway keeps the path shapes my currentintegration already uses:base URL: https://api-pr-2007.preview.experientiallabs.ai/api/v1auth: Authorization: Bearer $EXPLABS_API_KEY (the ONLY header needed)POST /chat/completions, /responses, /messages (Anthropic Messages API) andGET /models work unchanged. Plain OpenAI or Anthropic SDKs can also use thebare base https://api-pr-2007.preview.experientiallabs.ai/v1. Remove the provider-specific headers and requestfields from step 1: the gateway does provider routing (fallback, caching)itself and unknown parameters may be rejected. Send model + messages andonly the parameters I actually rely on.4. Map model ids. GET https://api-pr-2007.preview.experientiallabs.ai/api/v1/models with my key (free; this does notspend credits) lists the slugs I can call. For each model id from step 1,propose the matching slug (e.g. "claude-fable-5.1") and ask me to confirmthe mapping before replacing. Use slugs EXACTLY as returned.5. Move cost and usage reads over.- Every chat/responses reply carries usage.cost (USD, what I was charged)and usage.is_byok; on a stream it rides the final usage chunk. No flagneeded. Exception: a request sent with Idempotency-Key carries nousage.cost at all (original or replay), so read the field as optional.- One request: read the x-request-id response header and callGET https://api-pr-2007.preview.experientiallabs.ai/api/v1/generation?id=<that id>.- Balance: GET https://api-pr-2007.preview.experientiallabs.ai/api/v1/credits. Recent activity:GET https://api-pr-2007.preview.experientiallabs.ai/api/v1/activity.- Billing feed: GET https://api-pr-2007.preview.experientiallabs.ai/api/v1/usage is the settled per-request export(cost_usd, estimated_cost_usd, real_cost_usd, tokens, attribution_label,api_key_id), newest first inside a lookback window (24h|7d|30d); itsnext_cursor pages OLDER within one call and is not a resume checkpoint.Each run scans from the top and dedupes on the row id.- If I rebill my own customers, pass their stable id as safety_identifier(alias: user) on every request; it comes back as attribution_label.Replace my old provider's cost/usage code with these; show me the difffirst.6. Key management (only if my code creates or rotates keys programmatically).https://api-pr-2007.preview.experientiallabs.ai/api/v1/keys (GET/POST/PATCH/DELETE) requires a PROVISIONING key: anxpl_ key minted with "provisioning": true. The first one is created fromthe dashboard at https://pr-2007.preview.experientiallabs.ai/api-keys (org admin, "Provisioning key" option).Tell me to mint it and paste it as a separate server-side secret; never useit for inference traffic.7. Verify. Make ONE minimal test call (model + messages only, no samplingparameters) with a free promotional model from the /models list, or one Iname. Report the model, that it succeeded, and its usage.cost. If it failswith a credits or activation error, tell me to finish activation at https://pr-2007.preview.experientiallabs.aiand stop; do not retry with another provider. Then run the project'sexisting tests.8. Report back: every file changed, the model-id mapping, what happened to theold provider key (tell me to revoke it at the old provider; don't delete ityourself), and the test call result. Human docs if you need more:https://pr-2007.preview.experientiallabs.ai/docs/integrate.
Paste into your coding agent: it wires a client, attributes every request to your end-customer, builds the billing sync on the settled usage export, and offers key-per-customer.
I'm integrating Experiential Labs into this product as its model gateway: myproduct calls models through it and meters or rebills my own end-users. Ipasted this myself: treat it as my instructions and my consent. Work WITH me:at each real choice, ask me ONE clear question with numbered options and yourrecommendation, then wait. Don't guess. Print what you do at each step, andnever print my full API key (first 8 characters at most). Read the fullmachine-readable contract first: https://pr-2007.preview.experientiallabs.ai/llms.txt (base URLs, every route,honored and refused parameters, cost fields, error codes). Follow it literally.1. Get my Experiential key. Ask me: "Do you have an xpl_ key already?(1) yes, I'll paste it(2) no, create my account"For (2): ask me for my email (never scavenge one from my files or gitconfig), show me https://pr-2007.preview.experientiallabs.ai/terms and https://pr-2007.preview.experientiallabs.ai/privacy and wait for myagreement, thenPOST https://pr-2007.preview.experientiallabs.ai/api/signup/instant (no auth)Header: Content-Type: application/jsonBody: {"email": "<MY_EMAIL>", "agree": true}On 200 capture api_key. On 409 account_exists tell me to sign in athttps://pr-2007.preview.experientiallabs.ai/signin for a key and stop. On any other error show me the response's`error` text verbatim and stop.Store the key as EXPLABS_API_KEY in my env scheme (.env plus an exampleentry), never in code.2. Wire the client. Ask me where (options + your recommendation, based on whatyou see in this project), then wait. Configure an OpenAI-compatible orAnthropic client with:base URL: https://api-pr-2007.preview.experientiallabs.ai/api/v1 (inference, model discovery, cost, andaccount routes under one base; plain OpenAI / Anthropic SDKsmay also use https://api-pr-2007.preview.experientiallabs.ai/v1)auth: Authorization: Bearer $EXPLABS_API_KEY (the ONLY header needed)POST /chat/completions, /responses, or /messages (Anthropic Messages API).Name models by slug EXACTLY as GET https://api-pr-2007.preview.experientiallabs.ai/api/v1/models returns them(free; this does not spend credits). Send model + messages and only theparameters I actually rely on; unknown parameters may be rejected.3. Attribute every request to my end-customer. Pass their stable id assafety_identifier (alias: user) on every request. It comes back asattribution_label on the usage export, so I can group cost and tokens bymy own customer id with ONE key. Ask me what my customer id looks like andwire it through from where my code knows the customer.4. Read cost.- Inline: every chat/responses reply carries usage.cost (USD, what I wascharged) and usage.is_byok; on a stream it rides the final usage chunk.No flag needed, but a request sent with Idempotency-Key carries nousage.cost at all (original or replay), so read it as optional. Show itin my product where it helps; do not treat it as the billing record.- One request: read the x-request-id response header and callGET https://api-pr-2007.preview.experientiallabs.ai/api/v1/generation?id=<that id>.- Balance: GET https://api-pr-2007.preview.experientiallabs.ai/api/v1/credits (data.total_credits - data.total_usage).5. Build the billing sync on the settled export. Ask me which billing system Iuse (Metronome, Orb, Stripe metered billing, my own tables, or none yet),then write a scheduled job that:- reads GET https://api-pr-2007.preview.experientiallabs.ai/api/v1/usage?limit=1000 (settled rows, newest firstinside a lookback window: window=24h|7d|30d, default 7d; filterable byattribution_label, model, api_key_id, status). next_cursor({cursor_ts, cursor_id, cursor_after}, passed back as query params)pages OLDER within this one call and is NOT a checkpoint to resume fromnext run: each run starts at the top, follows next_cursor until a wholepage is older than the last successful run's start time minus a graceperiod covering my longest request, and dedupes on the row id. Scheduleit at least daily; rows older than 30 days are no longer exportable.- lands each row in a local outbox table keyed on the row id (insert, onconflict do nothing) in one local transaction, then in a separatedelivery step pushes unsent rows to the billing system and marks themsent (an external HTTP write cannot share my database transaction; theoutbox makes a crash between the two safe to replay),- sends one usage event per row: customer from attribution_label,transaction_id / idempotency key = the row id, timestamp = created_at,quantity = the cost column I choose (below) plus token counts if I meteron tokens; the margin is a rate in the billing system, not in this job.Cost columns: cost_usd is the platform credits charged; estimated_cost_usdis the attributed value of a BYOK row (served on my own provider key) atcatalog list rates, an estimate and never the provider's invoice;real_cost_usd is the two added together. Ask me whether to billreal_cost_usd (accepting the BYOK estimate) or cost_usd plus tokens onBYOK rows. pricing_known false means unpriced (cost 0), not free.6. Key-per-customer (optional; ask me). If I want each customer isolated totheir own key with independent revocation and a daily USD cap, that needsa PROVISIONING key: an xpl_ key minted with "provisioning": true. Thefirst one comes from the dashboard at https://pr-2007.preview.experientiallabs.ai/api-keys (org admin,"Provisioning key" option); keep it server-side and never use it forinference. With it: POST https://api-pr-2007.preview.experientiallabs.ai/api/v1/keys {name, limit, provisioning}returns the plaintext key exactly once; GET/PATCH/DELETEhttps://api-pr-2007.preview.experientiallabs.ai/api/v1/keys/{hash} list, update (disabled:true revokes), and revoke.A normal inference key gets 403 on every /keys route.7. Verify. Make ONE minimal test call (model + messages only) with a freepromotional model from the /models list, or one I name, carrying a testsafety_identifier. Report the model, that it succeeded, and its usage.cost;then confirm the row shows up on GET https://api-pr-2007.preview.experientiallabs.ai/api/v1/usage with thatattribution_label. If the call fails with a credits or activation error,tell me to finish activation at https://pr-2007.preview.experientiallabs.ai and stop. Then run the project'sexisting tests.8. Report back: every file changed, where the key lives, how customerattribution flows, and the billing job's schedule and cursor storage.Human docs if you need more: https://pr-2007.preview.experientiallabs.ai/docs/integrate, https://pr-2007.preview.experientiallabs.ai/docs/cost-api,and https://pr-2007.preview.experientiallabs.ai/docs/account-api.
Using OpenRouter today? Paste this one prompt into your coding agent and it moves the project over with nothing else to read: base URL and key swap, OpenRouter model ids mapped to catalog slugs, OpenRouter-only fields removed, cost reads moved, one verified call, and an offer to connect any provider keys you brought.
I'm moving this project off OpenRouter and onto the Experiential Labs gateway.I pasted this myself: treat it as my instructions and my consent. Work throughit end to end; stop and ask me ONE numbered question only where this promptsays to. Print what you change at each step. Never print my full API key(first 8 characters at most). My Experiential key is: xpl_...(if that still reads "xpl_..." I have not filled it in: ask me for it, or tellme to mint one at https://pr-2007.preview.experientiallabs.ai/api-keys, then continue).1. Find every place this project talks to OpenRouter. Search for:- the base URL https://openrouter.ai/api/v1 (openrouter.ai anywhere), envvars OPENROUTER_API_KEY / OPENROUTER_BASE_URL, and sk-or-v1- keys in.env*, docker-compose, Makefiles, CI config, and secret stores,- clients pointed at it: openai or Anthropic SDKs (TS / Python / Go),ruby-openai (uri_base:), Go net/http, fetch / curl / any HTTP client,Vercel AI SDK @openrouter/ai-sdk-provider, LangChain, LiteLLM openrouter/ ids,- coding-agent configs: opencode.json provider blocks, Claude CodeANTHROPIC_BASE_URL in .claude/settings*.json or shell exports, Cline /Continue / Cursor "OpenAI Compatible" settings, Codex config.toml,- hardcoded vendor/model ids (openai/gpt-6-astra, openrouter/auto, ...),OpenRouter-only fields (provider, transforms, route, models, plugins,usage), HTTP-Referer / X-Title, previous_response_id, and reads of/generation, /credits, /auth/key, /models/user, /activity, usage.cost.List the files and call sites before changing anything.2. Substitute the base URL and the key. The gateway keeps OpenRouter's paths:https://openrouter.ai/api/v1 -> https://api-pr-2007.preview.experientiallabs.ai/api/v1Authorization: Bearer $EXPLABS_API_KEY (the ONLY header needed)Store my key as EXPLABS_API_KEY in this project's env scheme (.env plus theexample file entry), never in code; point every OpenAI-compatible client atthe new base (a plain OpenAI SDK may also use https://api-pr-2007.preview.experientiallabs.ai/v1) andREPLACE URL variables such as OPENROUTER_BASE_URL with it. An Anthropic SDKappends /v1/messages itself: its base is the bare origin https://api-pr-2007.preview.experientiallabs.ai(never .../v1, which doubles to /v1/v1/messages). Do NOTdelete OPENROUTER_API_KEY or the OpenRouter key from .env, secret stores orCI: stop reading it, leave it in place; I revoke it at openrouter.ai/keys.A key COMMITTED in a config file (ANTHROPIC_AUTH_TOKEN in a checked-in.claude/settings.json) is already leaked: remove it there, never send it on.Coding agents: Claude Code uses ANTHROPIC_BASE_URL="https://api-pr-2007.preview.experientiallabs.ai"(no /v1); the key rides ANTHROPIC_API_KEY (never ANTHROPIC_AUTH_TOKEN) viaa shell export, the gitignored .claude/settings.local.json, or anapiKeyHelper reading .env, never the committed .claude/settings.json; remapEVERY model variable (ANTHROPIC_MODEL, ANTHROPIC_SMALL_FAST_MODEL,ANTHROPIC_DEFAULT_*_MODEL) to slugs or a background role keeps calling anexpensive model. OpenCode, Cline, Continue, Cursor and Codex take theOpenAI base https://api-pr-2007.preview.experientiallabs.ai/v1.3. Map model ids. Call GET https://api-pr-2007.preview.experientiallabs.ai/api/v1/models with mykey (free, spends no credits). EVERY entry carries canonical_slug, theplain slug the gateway serves; ids are usually vendor/slug (vendor/slug:freefor a free lane), sometimes a bare slug (gpt-6-astra, grok-4); ~vendor/x-latestids are rolling aliases, for projects that used OpenRouter's :latest ids.For each OpenRouter id from step 1: strip any :nitro, :floor, :online,:thinking, :extended, :beta or :exacto suffix (those variants do not existhere; only :free does), then match canonical_slug == the part after thevendor's slash (openai/gpt-6-astra -> gpt-6-astra, anthropic/claude-sonnet-5-> claude-sonnet-5, deepseek/deepseek-v4-flash -> deepseek-v4-flash).No match: look for the same model under a slightly different spelling anduse ONE obvious candidate, noted in the report. openrouter/auto and everyid still unmapped: ask me one question listing each with your bestcandidates from the list, then wait. Never guess a model I did not pick.Use canonical_slug EXACTLY as returned; a vendor/slug id works verbatimONLY when it is in the list (x-ai/grok-4 for the bare grok-4 answers 403model_not_granted: that means "use the canonical_slug", not an entitlementproblem). LiteLLM: model "openai/<slug>" (replace the "openrouter/" prefix)with api_base https://api-pr-2007.preview.experientiallabs.ai/api/v1 and api_key from the new var.4. Keep the request shapes (OpenAI Chat Completions and Responses bodies, SSEstreaming, tool calling, json_schema, response shapes). Strip EVERYOpenRouter-only field BEFORE the first call: each one left in is eithersilently ignored or its own 400 unsupported_parameter naming it in "param".- usage: {"include": true} (a guaranteed 400 today); for a stream sendstream_options: {"include_usage": true} instead (non-streams carry usage).- provider (order, allow_fallbacks, ignore, quantizations, sort, ...):accepted and silently ignored (not disclosed); the gateway routes andfails over itself. The one honored key is "provider": {"zdr": true}, aper-request zero-data-retention demand; keep exactly that if I used it.- transforms, route, models (fallback list: use its first model), plugins.- HTTP-Referer / X-Title headers: harmless, not shown; attribute via safety_identifier.Vercel AI SDK: replace @openrouter/ai-sdk-provider with @ai-sdk/openai(createOpenAI({ baseURL, apiKey })) or @ai-sdk/openai-compatible.OpenRouter's "reasoning": {"effort"} is translated to reasoning_effort bythe gateway (rewriting it is optional; a route with no reasoning drops it).Translated, dropped or adjusted fields are usually listed in the reply'sx-experiential-ignored-parameters JSON body field (not a header): informational.Anthropic-shaped traffic through OpenRouter (an Anthropic SDK, Claude Code)moves to the native Messages API, POST https://api-pr-2007.preview.experientiallabs.ai/api/v1/messages(SDK base: the bare origin, step 2), same key; no Idempotency-Key there.Responses API previous_response_id: continuation resolves ONLY while myorg's capture_prompt_content is on and within the retention window; withcapture off the second turn 400s previous_response_not_found. If theproject chains turns that way, readGET https://api-pr-2007.preview.experientiallabs.ai/api/orgs/<org_id>/telemetry-settings (org_id: /api/whoami);if off, ask me ONE question: turn it on (PUT the same route,{"capture_prompt_content": true}; it stores my prompts with Experiential)or rewrite the chain to resend the full conversation each turn.5. Move cost reads. Every chat / responses reply carries usage.cost (USD, whatI was charged) and usage.is_byok; on a stream it rides the final usagechunk (step 4's stream_options). A request sent with Idempotency-Keycarries no usage.cost at all, so read the field as optional. Same key onall of these, under https://api-pr-2007.preview.experientiallabs.ai/api/v1:GET /generation?id=<the x-request-id response header> one requestGET /usage settled per-request rows (api_key_id, cost) for billingGET /credits balance GET /key key info (OpenRouter's /auth/key)GET /activity per-day rollup (not per request)OpenRouter's /models/user has no equivalent: use /models. /usage is paginated(50 rows + next_cursor) and, like /activity, ORG-wide: filter ?api_key_id=<mykey's id, on every row> and match my x-request-id, or use /generation?id=.6. My own provider keys (BYOK). If step 1 found provider keys I routed throughOpenRouter (OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI, XAI, DEEPSEEK, AZURE,AWS/Bedrock, Fireworks, ...), do not drop them silently: ask me whether toconnect them so that traffic bills to my own accounts with no markup:GET https://api-pr-2007.preview.experientiallabs.ai/api/whoami -> org_idPUT https://api-pr-2007.preview.experientiallabs.ai/api/orgs/<org_id>/provider-connections/<provider>Content-Type: application/json {"secret": "<that provider key>"}(provider: openai, anthropic, gemini, xai, deepseek, or any other whosecredential is ONE string; never my OpenRouter key: I am leaving OpenRouter.azure_openai, bedrock, fireworks, vertex and modal need structured configor a token pair: connect those at https://pr-2007.preview.experientiallabs.ai/settings instead).Read check.status from the response and tell me it; if not "valid", tellme check.status_detail.remediation and stop. A 402 pro_required means aFIRST connection needs the Pro plan (https://pr-2007.preview.experientiallabs.ai/credits); an orgalready holding one keeps connecting. Never echo a key.7. Verify. Make ONE minimal call (model + messages, a small max_tokens) withthe CHEAPEST mapped slug: a reasoning model can cost cents even for asmoke, and an empty pricing object in the listing means unknown: readGET https://api-pr-2007.preview.experientiallabs.ai/api/models/<slug>, and if that 404s (an alias)price the model it resolves to (its canonical_slug) or skip it and smoke apriced slug. Stream if the project streams (add stream_options:{"include_usage": true} so the final chunk carries usage.cost); if theproject chains previous_response_id, verify a TWO-turn continuation, not asingle call. Report the model, that it succeeded, and its usage.cost, orread the cost from GET /api/v1/generation?id=<x-request-id>, which workseither way; then confirm the request's row on GET /api/v1/usage by thatx-request-id (I can also see it at https://pr-2007.preview.experientiallabs.ai/logs). On a creditsor activation error, tell me to finish activation at https://pr-2007.preview.experientiallabs.aiand stop; do not retry against OpenRouter. Then run the project's tests.8. Report back: every file changed; the model-id mapping and the ids I stillneed to decide; the OpenRouter-only fields removed; where EXPLABS_API_KEYlives; that the OpenRouter key stays in place for me to revoke; theverification result. Full contract: https://pr-2007.preview.experientiallabs.ai/llms.txt; humandocs: https://pr-2007.preview.experientiallabs.ai/docs/integrate.
Prefer to wire it by hand? The Quickstart makes the first call in a minute, and Coding agents has per-agent configuration.