Skip to main content
MarketplaceProvider Keys — your first call

Provider Keys — your first call

Three providers are live: Fal, Wavespeed and ElevenLabs. You call them with the Surplus API key you already have, and the discount comes off the provider's own list price. There is no second credential to collect and nothing to reserve.

This page is the end-to-end path for all three. The per-provider pages (Fal, ElevenLabs, Wavespeed) then give each one's exact routes and bodies.

One provider-key call, end to end
  1. Your requestSurplus key, provider's own body
  2. FenceHost and route checked first
  3. OfferCheapest live key that may serve
  4. Price & holdQuoted, then held on your credit
  5. Provider answersCharged actual, headers say what
Everything before the upstream call is ours: the fence, the offer, the price and the hold. A call we cannot price never reaches a seller's key at all — you are never billed an estimate for a plain call.

1. Get a key and credit

Any Surplus API key works — the same one you use for inference. The key market is prepaid credit only: it never falls through to the on-chain rail, so a wallet with USDC but no credit is refused rather than quietly charged on chain.

bash
export SURPLUS_API_KEY=sk_live_…
curl $SURPLUS_BASE_URL/payments/balance \
  -H "Authorization: Bearer $SURPLUS_API_KEY"

If the balance cannot cover the quote, the call answers 402 insufficient_credit and nothing is reserved.

2. Find out what is live

The book is public — no key needed — so you can check before you spend.

What is listed right now
curl $SURPLUS_BASE_URL/resource/markets

best_discount_pct is the deepest live offer and median_discount_pct is the middle one — the pair tells you whether that price survives one seller pausing. Pricing is the full treatment.

3. Make the call

The path after the provider id is the provider's own path. Two shapes, and getting this wrong is the single most common first mistake:

Path style — Wavespeed, ElevenLabsPOST /v1/resources/{provider}/{the provider's own path}
Header style — FalPOST /v1/resources/fal with an EMPTY path; the target rides in x-fal-target-url

Fal's SDK appends the model itself, so a URL that already carries the path is refused unexpected_path before anything else happens. Fal, end to end covers the SDK wiring.

The same call on each provider
# A one-second sound effect. Answers with audio bytes, not JSON.
curl -X POST $SURPLUS_BASE_URL/resources/elevenlabs/v1/sound-generation \
  -H "Authorization: Bearer $SURPLUS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"text":"a short soft chime","duration_seconds":1}' \
  --output chime.mp3 --dump-header -

Idempotency-Key is accepted on every write, but a provider-key relay is not replay-safe by design: a repeat is a second real generation at the provider and is billed as one. See jobs and settlement.

4. Read what it cost

Every response carries both numbers, on every rail:

  • x-si-buyer-cost-microinteger

    What you were charged, in microdollars. 1 USD = 1000000.

  • x-si-list-cost-microinteger

    What the provider would have billed for the same call, direct.

The difference is what the key market saved you. Both headers are CORS-exposed, so a browser client can read them too.

x-si-buyer-cost-micro: 1500
x-si-list-cost-micro: 3000

That call cost $0.0015 against a $0.003 list price — the seller's 50% off, applied to the provider's own quote rather than to a rate card of ours.

5. Jobs do not finish in step 4

Wavespeed predictions and Fal queue submits answer immediately with an id, not a result. The money follows the result, not the submit: the submit leaves the charge owed at the quote, and it settles at the actual figure when you fetch the result.

Where a job's money actually moves
  1. SubmitHold placed at the quote
  2. BoundJob pinned to that one offer, 27 h
  3. Poll statusFree — no charge for asking
  4. Fetch resultCharged the actual, hold released
The submit is not the end of the transaction. A job you never collect leaves the hold to expire rather than charging you for a result you never read.

Jobs and settlement is the whole mechanism, including the follow-up URL rewriting that keeps your polls on your own key.

Requiring something of the account

Some sellers advertise properties of the account behind their key — zero retention, an EU region, a business plan. Require any of them per call:

bash
curl -X POST $SURPLUS_BASE_URL/resources/elevenlabs/v1/sound-generation \
  -H "Authorization: Bearer $SURPLUS_API_KEY" \
  -H "X-SI-Require: data.zdr,residency.eu" \
  -d '{"text":"a short soft chime","duration_seconds":1}'

A call that requires something only reaches offers claiming all of it. If none can, it is refused trait_unavailable rather than quietly served by an offer that does not qualify — which is the point, and also why requiring something can raise your price. GET /v1/resource/traits lists what is requirable, and Provider Keys explains what each badge is actually worth.

Routing only to deep discounts

The min{N} mirror works here exactly as it does for inference — prefix the path and only offers at least N% off are considered:

bash
curl -X POST https://api.surplusintelligence.ai/min40/v1/resources/wavespeed/api/v3/wavespeed-ai/flux-schnell \
  -H "Authorization: Bearer $SURPLUS_API_KEY" \
  -d '{"prompt":"a tiny blue paper boat","size":"1024*1024"}'

If nothing is that cheap you get no_resource_offer rather than a worse price. Minimum-discount routing has the details.

When a call does not land

Each refusal names one cause, so you can tell whose problem it is:

unexpected_pathStatus · 400What to do · A header-style provider (Fal) was given a path. Empty it.
platform_route_refusedStatus · 403What to do · Never reachable, for any seller. Not a pricing or availability problem.
policy_refusedStatus · 403What to do · Offers exist; no seller's rules allow this call.
no_resource_offerStatus · 404What to do · Nobody lists this provider, or none is this cheap.
job_not_foundStatus · 404What to do · The job is not yours, or its binding expired after 27 h.
seller_cap_reachedStatus · 429What to do · Every capable offer spent its daily cap. Resets 00:00 UTC. Retryable.
offers_unhealthyStatus · 503What to do · Every capable offer is backed off after failures. Retryable.
provider_unpriceableStatus · 400What to do · We cannot price it, so we refuse rather than guess. Use a priced model.
trait_unavailableStatus · 404What to do · Nobody advertises what you required. Retryable.
insufficient_creditStatus · 402What to do · Add prepaid credit. Nothing was reserved.