Theme
Language

Supplier machine API

The supplier marketplace machine API: mint an sk-sup-… key in the cabinet, call every endpoint with Authorization: Bearer, onboard connections in batches and read connections, offers, price changes, earnings and statistics.

The supplier cabinet has a machine surface: a supplier can onboard accounts in bulk and read their own connections, offers, prices, price-change history, earnings and statistics from a script, using a supplier-scoped API key instead of a browser session.

This is additive. The browser cabinet is unchanged, and the machine routes assemble the same payloads the cabinet pages do, so the two surfaces cannot report different numbers.

Get a key

Machine keys are minted and revoked in the supplier cabinet. The full token is shown once, at creation, and is never returned again.

  1. Open the supplier cabinet and find the Machine API keys section.
  2. Give the key a label (optional) and press create.
  3. Copy the token immediately. It starts with sk-sup-.
  4. Store it in a secret manager or an environment variable. Never commit it or send it in a support message.
Keys are hashed, not encrypted: nobody, including an operator, can recover a lost key. Revoke it and issue a new one. A supplier can hold at most 20 active keys.

Cabinet management endpoints

These routes use the cabinet session or tracking token. They deliberately do not accept a machine key, so a leaked machine key cannot mint or revoke other keys.

ParameterTypeDescription
GET /api/marketplace/suppliers/me/api-keyslistList keys: id, label, prefix, active, lastUsedAt, createdAt. Never the token or its hash.
POST /api/marketplace/suppliers/me/api-keysmintBody { "label"?: string }. Returns { "key": "sk-sup-…", "apiKey": { … } } — the only time the token appears.
DELETE /api/marketplace/suppliers/me/api-keys/{id}revokeRevoke one key. 404 when the id does not belong to the caller.

Authentication

Every machine route requires the supplier key as a bearer token:

Authorization: Bearer sk-sup-<64 hex>
curl https://getvibeapi.com/api/marketplace/suppliers/api/v1/connections \
  -H "Authorization: Bearer $SUPPLIER_API_KEY"

A request resolves the key to exactly one supplier, and every query is filtered by that id. Revocation is scoped by both the key id and its owner, so a supplier cannot revoke another supplier’s key. Never log or transmit the key.

A missing, unknown or revoked key answers one fixed 401 message, so a caller cannot tell the cases apart. Send the key only over HTTPS.

Read endpoints

All are GET, API-key authenticated and scoped to the authenticated supplier. Micro-USD money is returned as strings; token counts are numbers.

Connections

GEThttps://getvibeapi.com/api/marketplace/suppliers/api/v1/connections

The supplier’s connected accounts, each with what it has earned (payable only).

{
  "connections": [
    {
      "id": "…",
      "connectionType": "subscription-api-key",
      "subscriptionProductLabel": "…",
      "verifiedEndpoint": "https://…",
      "status": "ACTIVE",
      "enabled": true,
      "verificationState": "verified",
      "verifiedBy": "…",
      "label": "nightly-1",
      "account": "…",
      "verifiedModels": ["…"],
      "servingModels": ["…"],
      "lastVerifiedAt": "2026-09-18T09:00:00.000Z",
      "proxy": "…",
      "proxySource": "pool",
      "proxyCountry": "de",
      "proxyExpiresAt": "2026-10-18T09:00:00.000Z",
      "proxyExpiryDays": 30,
      "proxyLost": false,
      "probedVia": "…",
      "lastError": null,
      "needsReauth": false,
      "accountLimits": null,
      "accountLimitsSource": null,
      "accountLimitsCheckedAt": null,
      "earnings": { "earnedMicros": "1250000", "requestCount": 42 },
      "createdAt": "2026-09-01T09:00:00.000Z"
    }
  ]
}

Offers

GEThttps://getvibeapi.com/api/marketplace/suppliers/api/v1/offers

The supplier’s offers with the current prices and the live percentage of the official card.

{
  "offers": [
    {
      "id": "…",
      "baseModel": "claude-opus-5",
      "claimedModel": "claude-opus-5",
      "providerLabel": "…",
      "status": "ACTIVE",
      "statusReason": null,
      "inputMicrosPer1M": "1000000",
      "outputMicrosPer1M": "2000000",
      "cacheReadMicrosPer1M": null,
      "blendedPctOfOfficial": "0.42",
      "officialPrice": null,
      "pctOfOfficial": 42,
      "trafficTier": "…",
      "cooldownUntil": null,
      "cooldownReason": null,
      "firstVerifiedAt": "2026-09-01T09:00:00.000Z",
      "activatedAt": "2026-09-01T09:00:00.000Z",
      "lastManualPriceChangeAt": null,
      "maxConcurrentRequests": 8,
      "servingEnabled": true
    }
  ]
}

Price-change history

GEThttps://getvibeapi.com/api/marketplace/suppliers/api/v1/offers/{offerId}/price-changes

The price-change ledger for one of the supplier’s own offers: planned, applied and cancelled changes. An offer belonging to another supplier answers 404.

{
  "offerId": "…",
  "schedules": [
    {
      "id": "…",
      "offerId": "…",
      "priceInUsd": "1.000000",
      "priceOutUsd": "2.000000",
      "effectiveFrom": "2026-10-01T00:00:00.000Z",
      "createdAt": "2026-09-18T09:00:00.000Z",
      "cancelledAt": null,
      "appliedAt": null
    }
  ]
}

Statistics

GEThttps://getvibeapi.com/api/marketplace/suppliers/api/v1/stats

The same shape the cabinet statistics page shows: totals, a 14-day daily series and a per-offer byOffer breakdown.

{
  "totals": {
    "requests": 12000,
    "successes": 11880,
    "errors": 90,
    "timeouts": 30,
    "successRatePct": 99,
    "promptTokens": 9000000,
    "completionTokens": 4000000,
    "cacheTokens": 2500000,
    "sourceCostMicros": 12345678,
    "avgLatencyMs": 812.4,
    "p50LatencyMs": 640,
    "p95LatencyMs": 2100
  },
  "daily": [
    { "date": "2026-09-05", "requests": 800, "successes": 795, "errors": 4, "promptTokens": 600000, "completionTokens": 250000, "sourceCostMicros": 900000 }
  ],
  "byOffer": [
    { "offerId": "…", "baseModel": "claude-opus-5", "requests": 12000, "successRatePct": 99, "promptTokens": 9000000, "completionTokens": 4000000, "tokens": 13000000, "sourceCostMicros": 12345678, "hitRate": 0.28, "effTotal": 3.14, "rank": 1 }
  ]
}

Earnings

GEThttps://getvibeapi.com/api/marketplace/suppliers/api/v1/earnings

Up to 500 recent settlement-eligible route attempts, newest first.

{
  "events": [
    {
      "id": "…",
      "baseModel": "claude-opus-5",
      "result": "SUCCESS",
      "promptTokens": "1200",
      "completionTokens": "800",
      "paidMicros": "420000",
      "settlementEligible": true,
      "finishedAt": "2026-09-18T09:00:00.000Z",
      "settlementStatus": "pending_or_settled"
    }
  ]
}

Create connections

POSThttps://getvibeapi.com/api/marketplace/suppliers/api/v1/connections

Create one account or a whole pack from a credential you already hold — no browser OAuth round-trip. The body is one item, a { "items": [ … ] } envelope, or a bare array. All three are normalised to the same per-item result. The older /api/marketplace/suppliers/api/v1/connections/batch path is an alias of the same handler.

Credential shapes

Every item names the pool with provider (the readable pool name, e.g. codex or claude-code) and carries exactly one credential shape:

ParameterTypeDescription
codexAuthJsoncodex-bundleThe Codex CLI ~/.codex/auth.json pasted verbatim: auth_mode, tokens.{id_token,access_token,refresh_token,account_id}, _meta.{plan_type,email}.
accessToken + refreshTokenclaude-tokensThe Claude Code access token (sk-ant-oat01-…) and its refresh token.
refreshTokenantigravity-refreshAn Antigravity refresh token.
apiKeyapi-keyA ready subscription API key.
bindToken + oauthCodeoauth-codeThe OAuth result from the browser flow, when you used it instead of a pasted bundle.

Every item carries a working egress proxy, and there is no proxy-less connection. Pass your own proxy, or a proxyCountry to prefer one of ours; pass neither and the server assigns and proves one of its own before any vendor request. If no pool proxy can be proved, the item is refused as proxy_unavailable. externalId is echoed back untouched for correlation.

curl https://getvibeapi.com/api/marketplace/suppliers/api/v1/connections \
  -H "Authorization: Bearer $SUPPLIER_API_KEY" \
  -H "Content-Type: application/json" \
  --data @pack.json

pack.json — one own proxy and one country-pool proxy:

[
  {
    "externalId": "codex-1",
    "provider": "codex",
    "connectionLabel": "nightly-codex-1",
    "codexAuthJson": "{\"auth_mode\":\"chatgpt\",\"tokens\":{\"id_token\":\"…\",\"access_token\":\"…\",\"refresh_token\":\"…\",\"account_id\":\"…\"},\"_meta\":{\"plan_type\":\"plus\",\"email\":\"…\"}}",
    "proxy": { "scheme": "http", "host": "proxy.example.com", "port": 8899, "username": "u", "password": "p" },
    "offers": [{ "baseModel": "deepseek-v4.1-flash", "inputMicrosPer1M": 1000000, "outputMicrosPer1M": 2000000 }]
  },
  {
    "externalId": "claude-1",
    "provider": "claude-code",
    "connectionLabel": "nightly-claude-1",
    "accessToken": "sk-ant-oat01-…",
    "refreshToken": "sk-ant-ort01-…",
    "proxyCountry": "de",
    "offers": [{ "baseModel": "claude-opus-5", "inputMicrosPer1M": 1000000, "outputMicrosPer1M": 2000000 }]
  }
]
Re-posting the same account is safe: the credential fingerprint is unique, so a retry returns a per-item duplicate refusal and writes nothing new. Retry a failed pack item by item.

Partial success is the contract

Each item is proved against the vendor and written on its own. One bad row never fails the batch, and an item is reported ok: true only after its connection row is committed.

{
  "supplierId": "…",
  "accepted": 1,
  "rejected": 1,
  "results": [
    {
      "index": 0,
      "externalId": "row-1",
      "ok": true,
      "connectionId": "…",
      "connectionType": "subscription-api-key",
      "verificationState": "verified",
      "verifiedModels": ["…"],
      "subscriptionProduct": "codebuddy-cn",
      "verifiedEndpoint": "https://…",
      "latencyMs": 210
    },
    {
      "index": 1,
      "externalId": "row-2",
      "ok": false,
      "code": "bind_session_invalid",
      "error": "the authorization session expired or did not match"
    }
  ]
}

Per-item refusal codes

ParameterTypeDescription
invalid_credentialcodeThe vendor rejected the credential shape or value.
connection_type_unavailablecodeThat connection type is not available yet.
subscription_product_unavailablecodeThe named subscription product is not offered.
provider_unavailablecodeThe selected provider is not available.
bind_session_invalidcodeThe OAuth session expired or did not match.
proxy_requiredcodeThe resolved proxy had no usable URL. (An item that names no proxy is assigned one instead.)
proxy_unavailablecodeNo pool proxy could be proved for the requested country, or for any country when none was named.
proxy_race_lostcodeThat proxy was taken by another connection just now.
probe_failedcodeThe vendor rejected the credential during the live probe.
model_not_servedcodeThe account did not confirm a requested model; the refused models are in the item's "models" array.
duplicatecodeThe same credential fingerprint is already connected.
encryption_unavailablecodeCredential encryption is not configured on the project.
internal_errorcodeAn unexpected server error. Retry the single item later.
A refusal never carries a credential, token or OAuth code. Refusals are logged with the item index and code only.

Proxy pre-flight

POSThttps://getvibeapi.com/api/marketplace/suppliers/proxy-check

Prove a proxy before you hand over a credential: give your own proxy or a proxyCountry and the server opens the same tunnel it will use for the connection and reaches a neutral host through it. This is only a pre-flight — the create call runs the identical check and refuses before it exchanges a token or probes the vendor, so a broken proxy never costs a credential.

curl https://getvibeapi.com/api/marketplace/suppliers/proxy-check \
  -H "Content-Type: application/json" \
  -d '{ "proxy": { "scheme": "http", "host": "proxy.example.com", "port": 8899, "username": "u", "password": "p" } }'
{ "ok": true, "outcome": "ok", "latencyMs": 42 }
The response carries an outcome and a latency only. It never echoes the proxy URL, its userinfo or the exit address. A failure answers 422 with outcome: "proxy_failed"; a country with no free pool proxy answers 409 with proxy_unavailable.

Browser OAuth (cabinet)

The cabinet’s own two-step OAuth flow, for when you link an account in a browser instead of holding a bundle:

POSThttps://getvibeapi.com/api/marketplace/suppliers/connect/start

Body { "connectionType": "claude-code" | "codex-oauth" }. Returns the authorizeUrl to open and the signed bindToken that ties the code to the PKCE session. Nothing is persisted.

POSThttps://getvibeapi.com/api/marketplace/suppliers/connect

Submits the completed grant — the bindToken plus the oauthCode and the same offers / proxy fields as a create item. The proxy is proved before the code is exchanged. These two routes use the cabinet session; a machine key cannot call them (use POST /connections with bindToken + oauthCode instead).

Rate limits

ParameterTypeDescription
Create connectionslimitAt most 25 items per call. 20 calls per hour per supplier, on top of a 120/hour per-IP cap. Each item is an outbound vendor probe.
Proxy pre-flightlimit30 calls per hour per IP. Each call opens one tunnel to a neutral host.
Read endpointslimit600 requests per hour per IP for the shared machine surface unless a route sets its own cap.
Cabinet key managementlimit120/hour per IP to list keys, 20/hour to mint, 60/hour to revoke.
A 429 response carries Retry-After in seconds. Back off and retry after that delay; re-submitting the same credential is refused as duplicate by the unique credential fingerprint.

Error responses

ParameterTypeDescription
401statusMissing, unknown or revoked API key. One fixed message, so a caller cannot distinguish the cases.
404statusThe path does not exist on this project (the marketplace is not enabled here), or the addressed offer belongs to another supplier.
429statusRate limit. Retry-After is returned by the shared limiter.
400statusMalformed JSON or a batch over the cap. The body names the invalid input.

A machine-readable description of every endpoint is part of the OpenAPI document at /api/openapi. Point an OpenAPI client generator at it to build a typed client.

Supplier machine API — sk-sup keys, batch onboarding, reads | GetVibe API