> For the complete documentation index, see [llms.txt](https://mute-sh.gitbook.io/mute.sh/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mute-sh.gitbook.io/mute.sh/integration-guides/maker-onboarding.md).

# Market Maker Onboarding

This is the **operational SOP** for going from zero to a live, quoting market maker on `parlay.mute.sh/v2` — registration, key issuance, tier status, and the connect walkthrough. For protocol mechanics (pricing, EIP-712 signing, field-match rules) see the [Market Maker Guide](/mute.sh/integration-guides/maker-guide.md). For raw frame schemas see [WebSocket Events](/mute.sh/reference/ws-events.md).

{% hint style="warning" %}
**Testnet only.** All contracts are deployed on HyperEVM testnet (chainId `998`). Mainnet is not yet live.
{% endhint %}

***

## 1. Trust model — what "onboarding" actually gates

The relay is a neutral broker: it never holds your funds and never sees your private key. Two independent things gate you today, and it's important to separate them:

1. **Connection** — gated by a single shared API key (`MM_API_KEY`). This is what "issuing you a key" means in practice (§2).
2. **Winning trades** — gated by an on-chain standing USDC allowance to the escrow. You can authenticate successfully and still lose every auction if you skip this (§4, step 3).

There is **no per-maker registry, no approval queue, and no tiering** in the current relay — every authenticated maker with a standing allowance competes as a peer in one flat pool. Your real identity is the maker address recovered from your quote signature, not any client-supplied label (`mmId`) — the relay forces `maker`/`mmId` to your authenticated session on every quote ([Market Maker Guide §4](/mute.sh/integration-guides/maker-guide.md)).

***

## 2. Registration & approval process

There is no self-serve signup form or on-chain registry today. The process is manual and operator-mediated:

**Step 0 — Contact the operator.** Reach out to the mute.sh / relay operator (same channel as [README.md](/mute.sh/readme.md)'s demo-access process). Provide:

* The maker EOA address(es) you'll sign quotes with.
* Expected volume / stake range you plan to quote.
* Whether you want [last look](/mute.sh/integration-guides/maker-guide.md#9-last-look) enabled.
* Which builder(s) you intend to quote for, if you're integrating for a specific builder rather than the open pool.

**Step 1 — The operator issues an API key out-of-band.** This is the entirety of "getting a prod API key" today: the relay authenticates every maker against a single server-side `MM_API_KEY` environment variable. There is no per-maker key, no key rotation self-service, and no scoping by address — "issuing you a key" means the operator hands you the current shared secret string over a secure channel (not email, not Slack in plaintext).

{% hint style="warning" %}
**This is a shared secret, not a per-MM credential.** Every connected maker presents the identical `apiKey` value. Treat it as sensitive — if it leaks, any holder can open a maker session (though they still can't sign your quotes or touch your funds; see §6). Rotating it means the operator changes the env var for **all** makers simultaneously, so coordinate before requesting a rotation.
{% endhint %}

**Step 2 — Fund your maker address.** You need testnet USDC (`0x75b69d0E8fA3CdB644b0f069E4e876B85A76E137`) to post `makerCollateral`. You do **not** need native gas — the relayer submits all on-chain transactions and the standing-allowance permit is gasless to you ([Market Maker Guide §8](/mute.sh/integration-guides/maker-guide.md#8-standing-allowance)).

**Step 3 — Sign and submit your standing allowance.** This is covered in detail in §4 below; it's the real "activation" step, distinct from key issuance.

***

## 3. Tier-gating: Prime vs Institutional

{% hint style="danger" %}
**Not yet implemented.** There is no tier field, no role beyond a single `"maker"`, and no per-MM record anywhere in the relay. A repo-wide search of the Parlay relay and SDK source for `tier`, `Prime`, or `Institutional` returns zero hits. If you were told "Prime" or "Institutional" access exists as a live product today, that is not accurate — this section describes what those terms *would* map onto if built, not a process you can enroll in now.
{% endhint %}

### What exists today: one flat, open pool

Every maker that completes auth (§4) and has a standing allowance (§4 step 3) is a peer:

* **Equal RFQ fan-out** — every open RFQ is broadcast to every connected maker, with no priority ordering.
* **Equal auction treatment** — the winner is whoever offers the taker the highest payout (lowest effective edge), full stop. There is no tier-based tie-break or reserved allocation ([Market Maker Guide §11](/mute.sh/integration-guides/maker-guide.md#11-winning-quote-selection)).
* **Self-serve go-live** — once you're authed and approved, you're live. There's no separate "activation" gate beyond the standing allowance.

### The conceptual model these terms would map onto (aspirational, not built)

If tiering were built, the natural mapping onto existing (also partially aspirational) concepts would look like:

| Term                | Would likely map onto                                                                          | Status                                                                                                                                                                                                                         |
| ------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **"Prime"**         | Per-maker API keys + a maker registry, possibly with elevated stake caps or priority fan-out   | Not implemented — no per-key infra exists                                                                                                                                                                                      |
| **"Institutional"** | A hypothetical builder-level `bookMode: "managed"` dedicated-liquidity pool + a negotiated SLA | **Not implemented** — `bookMode` has no code path in the deployed relay, and the [Builder Guide](/mute.sh/integration-guides/builder-guide.md) does not document any such concept; every builder is effectively `"open"` today |

Two important distinctions if this is ever built:

* A hypothetical `bookMode: "managed"` would be a **builder-level** concept — it would restrict which MMs receive a *specific builder's* RFQs. It is not an MM-side tier you'd apply for directly; a builder would configure it and invite specific MMs into their pool.
* Neither concept currently changes stake limits, fee treatment, or auction priority. `MAX_STAKE_USD` / `MIN_STAKE_USD` and the fee regime are global relay config today, not per-maker.

**If you need dedicated-liquidity terms, custom stake limits, or an isolated MM pool**, contact the operator to discuss a managed deployment — the same ask the [Builder Guide §12, Custom Relay Deployment](/mute.sh/integration-guides/builder-guide.md#12-custom-relay-deployment) points builders toward. This is a conversation, not a self-serve tier upgrade.

***

## 4. Step-by-step: get a prod key and connect

{% hint style="warning" %}
**If you're reading an older reference (or code) that uses a `hello`/`welcome` handshake:** that's an earlier, unrelated relay protocol generation. The **deployed v2 relay** (the one behind `parlay.mute.sh/v2`) accepts a different message — the `auth` frame shown below — and does not recognize `hello` as an auth message; sending it will just hit the auth-timeout disconnect. [Market Maker Guide §4](/mute.sh/integration-guides/maker-guide.md#4-registration) and [WebSocket Events §3.7](/mute.sh/reference/ws-events.md#37-maker--server-auth) both document this same real `auth` handshake in full.
{% endhint %}

{% hint style="success" %}
**Recommended: don't hand-roll this.** The `@mutesh/parlay-maker` package is a published, wire-verified TypeScript client for exactly this channel — it sends the `auth` frame, signs your standing-allowance permit, prices and signs `ParlayQuote`s, and handles reconnects for you. The raw-frame walkthrough below is here so you understand what the SDK is doing under the hood (and so you can hand-roll a client in another language), but a TypeScript integration should start from the SDK, not from raw WebSocket frames.
{% endhint %}

**1. Obtain the key.** See §2 — the operator gives you the current `MM_API_KEY` value out-of-band.

**2. Choose your endpoint.**

| Environment | URL                              |
| ----------- | -------------------------------- |
| Production  | `wss://parlay.mute.sh/v2/ws/rfq` |
| Local dev   | `ws://localhost:4001/ws/rfq`     |

{% hint style="info" %}
The `/v2` segment in the production URL is a reverse-proxy prefix that's stripped before the request reaches the relay process — the Bun server itself binds the path `/ws/rfq` with no `/v2` prefix. That's why the local-dev URL has no `/v2` in it. If you're debugging a 404-shaped connection failure against `localhost`, this is the first thing to check.
{% endhint %}

**3. Open the socket and send an `auth` frame within 30 seconds.** The relay closes any unauthenticated socket with WS code `1008` (`"auth timeout"`) after `V2_WS_AUTH_MS` (default 30,000ms, operator-configurable). Send exactly this shape (the `@mutesh/parlay-maker` client builds this frame for you when you call `connect()`):

```jsonc
{
  "type": "auth",
  "auth": { "apiKey": "<key from the operator>" },
  "identity": {
    "maker_address": "0x...",   // the address your quote signatures must recover to
    "signer_address": "0x...",  // typically the same address as maker_address
    "signature_type": 0         // MUST be 0 (EOA) — anything else is rejected
  },
  "last_look": false,           // opt into last-look confirmation; default false
  "approval": {                 // OPTIONAL but strongly recommended on first connect — see step 4
    "value": "...", "deadline": "...", "v": 27, "r": "0x...", "s": "0x..."
  }
}
```

Field notes:

* `signature_type` must be `0` (EOA-only support today) — any other value is rejected with `INVALID_IDENTITY`.
* `maker_address` and `signer_address` are both required and must be well-formed addresses, or auth fails with `"maker_address and signer_address required"`.
* `auth.secret` and `auth.passphrase` are accepted fields in the message shape (kept for parity with Polymarket-style L2 auth headers) but are **not validated** — only `auth.apiKey` gates the connection today. Don't rely on them for anything.

**4. Include your standing-allowance `approval` on first connect.** This is the step new MMs most often skip, and skipping it means you authenticate fine but **lose every auction silently** — a maker with no standing allowance has its quotes rejected with `ALLOWANCE_VALIDATION_FAILED` ("maker has no standing allowance"). The `approval` field is an EIP-2612 permit signature; see [Market Maker Guide §8](/mute.sh/integration-guides/maker-guide.md#8-standing-allowance) for how to construct it. The relay submits it on-chain for you and skips the transaction entirely if you already hold an allowance at or above its "effectively unlimited" threshold — so re-sending `approval` on every reconnect is harmless (it becomes a no-op read once you're already approved).

**5. Expect the reply.**

Success:

```jsonc
{ "type": "auth", "success": true, "address": "0x...", "role": "maker" }
```

Failure (socket stays open; you may retry with a corrected frame):

```jsonc
{ "type": "auth", "success": false, "error": "invalid apiKey" }
// or: "apiKey required" | "maker_address and signer_address required"
```

**6. You're connected — now what.** From here you'll receive RFQ broadcasts, price them, and send back signed quotes. This part of the flow (pricing, EIP-712 signing, field-match rules, nonce handling) is unchanged from what's already documented — hand off to [Market Maker Guide §5 onward](/mute.sh/integration-guides/maker-guide.md#5-pricing) and [WebSocket Events](/mute.sh/reference/ws-events.md) for the full schemas.

***

## 5. Go-live checklist

* [ ] Received the current `MM_API_KEY` from the operator over a secure channel
* [ ] Maker address funded with testnet USDC
* [ ] Sent an `auth` frame (not `hello`) with a valid `approval` and received `{ success: true }`
* [ ] Confirmed the standing allowance actually landed on-chain (or that a pre-existing allowance was already above the auto-skip threshold)
* [ ] Quoted at least one RFQ end-to-end against the live relay — the v2 demo orchestrator (see [README.md](/mute.sh/readme.md#running-the-demo) for the current invocation) is the fastest way to confirm this without waiting for organic taker flow
* [ ] Confirmed reconnect behavior — the relay expects you to re-auth after any disconnect; the `@mutesh/parlay-maker` client reconnects with backoff automatically, or mirror that behavior if you hand-rolled your own client
* [ ] Your maker key is a **distinct address** from any taker key you use for testing — the escrow unconditionally reverts on `maker == taker` self-trades ([Market Maker Guide §13](/mute.sh/integration-guides/maker-guide.md#13-self-trade-guard)). The relay does not pre-filter this at quote-submission time, so if you win an auction against your own RFQ the on-chain transaction reverts and you'll see a `FAILED` execution update (`TRADE_SUBMISSION_FAILED`) instead of a fill — not a silent drop, but a wasted round-trip you can avoid by never quoting from your taker-test address

***

## 6. Security & key hygiene

* **Never commit the API key** to a repo, even a private one. It's a bearer credential for the shared maker pool.
* **Your maker private key never leaves your process.** The relay only ever receives your address and your EIP-712 signatures — the API key gates the *connection*, not your signing key.
* **Deterministic demo keys are public.** The demo profiles (`mm_alpha`, `mm_bravo`, etc.) use a key derived as `keccak256(toBytes("parlay-mm-demo-v1:<mmId>"))` — anyone can derive these. Never use them beyond local testing.
* **Rotation is operator-driven and affects everyone.** Because the key is shared, ask the operator before assuming a rotation only affects you.

***

## Cross-links

| Doc                                                              | What's in it                                                                          |
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| [Market Maker Guide](/mute.sh/integration-guides/maker-guide.md) | Pricing, EIP-712 quote signing, fee regime, combo conflict checks, field-match guards |
| [WebSocket Events](/mute.sh/reference/ws-events.md)              | Full frame-by-frame schema reference                                                  |
| [Builder Guide](/mute.sh/integration-guides/builder-guide.md)    | Builder identity resolution, fee splits, RFQ creation, combo conflict checks          |
| [Cashout](/mute.sh/integration-guides/cashout.md)                | Buying out a live parlay's taker side as an MM                                        |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://mute-sh.gitbook.io/mute.sh/integration-guides/maker-onboarding.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
