Onboarding
Getting setup to quote on Flint
Audience
This page assumes you're either:
- Building a market-maker bot. You'll quote on at least one pair and need a
maker_idregistered against your pubkey. - Building a read-only integration (analytics, charts, alerts). Public market data, aggregate stats, and historical backfills need no auth.
1. Get an endpoint
The server binds two gRPC listeners so operators can front each with a different ingress policy (public CDN/cache vs. mTLS / authenticated edge):
| Listener | Default port | Services | Auth |
|---|---|---|---|
| Public | 50051 | MarketDataService, StatsService, HistoricalService, AuthService | None — public. |
| Authed | 50052 | AuthService, MakerService, TxService | Bearer session token for all except AuthService. |
AuthService is available on both listeners. The public listener is enough for login flows; makers also configure the authed listener because the tokens it mints are used by MakerService and TxService.
| Environment | Public | Authed |
|---|---|---|
| Mainnet | https://api.superis.exchange:443 | https://auth.api.superis.exchange:443 |
| Testnet | https://testnet.api.superis.exchange:443 | https://auth.testnet.api.superis.exchange:443 |
| Localhost | http://localhost:50051 | http://localhost:50052 |
(SUPERIS_INSECURE=1 tells the SDKs to skip TLS for local hosts.)
Market-data, stats, historical, and browser login integrations only need the public endpoint. Makers need the authed endpoint too.
2. Solana wallet
You need an Solana keypair. The same key:
- Authenticates with the gRPC server (signs the AuthService challenge).
- Signs on-chain quoting transactions (
UpdateOracleFair,UpdateQuotingParams).
The server only accepts authenticated calls from pubkeys that are registered as quoting authorities for some maker_id.
3. Register your pubkey as a quoting authority
If you don't already have a maker_id, the on-chain admin needs to create one for you. Maker creation is a one-time CreateMaker instruction signed by the admin; ask the operator that runs your deployment.
If you already have a maker_id and want to delegate quoting to a hot wallet, send a ManageMaker { AddQuoter } instruction to the Flint program from the maker admin wallet, naming the hot wallet as the new quoter.
Hot vs. cold wallets
Use a cold wallet to mint your maker_id and set max_balance / risk params (the admin path). Use a delegated hot wallet for the high-frequency UpdateOracleFair / UpdateQuotingParams flow.
4. Fund the maker
Flint allocates liquidity dynamically at swap time — not when you publish a quote. When a taker hits your book, the matcher reads your current balance and caps the fill against:
- on the sell side of the fill (the token going out of your account):
available_to_sell= your deposited balance of that token. - on the buy side of the fill (the token coming in):
available_to_buy=soft_max_balance − balance— the headroom under your cap.
Because the check happens at swap time, two properties fall out that surprise people coming from a CEX:
You can publish levels larger than what you currently hold. Quotes aren't rejected on size. The matcher fills up to whatever budget exists at the moment of the swap. A 10 SOL ask with 5 SOL deposited fills 5 SOL.
Fills feed adjacent quotes. A SOL ask that pays out SOL brings USDC in. That USDC immediately becomes
available_to_sellUSDC backing any SOL bid you also posted — the bid can then fill on the very next swap. A maker can run a two-sided book on a one-sided initial deposit; inventory cycles through the quotes.
Worked examples (which balance gates which side of each fill):
| Your quote | Sell-side budget — deposited | Buy-side budget — cap with headroom |
|---|---|---|
| Sell SOL on SOL/USDC | SOL deposited in the SOL micro-book | USDC soft_max_balance on the global market |
| Buy SOL on SOL/USDC | USDC deposited in the global market | SOL soft_max_balance on the SOL micro-book |
| Sell SOL on SOL/ETH | SOL deposited in the SOL micro-book | ETH soft_max_balance on the ETH micro-book |
| Buy SOL on SOL/ETH | ETH deposited in the ETH micro-book | SOL soft_max_balance on the SOL micro-book |
The same rule explains both modes — SOL/USDC just keeps the USDC side in the singleton GlobalMarket account instead of a per-spot micro-book. Each fill is a single two-token settlement; nothing is multihop.
Two on-chain accounts hold these balances:
| Account | Set by | Purpose |
|---|---|---|
SpotMakerMicroBook.balance (one per spot) | DepositWithdraw + UpdateQuotingParams.max_balance | Deposited base + per-spot soft_max_balance cap. |
GlobalMarket.balances[maker_id] (singleton) | DepositWithdrawQuote + set_quote_max_balance | Deposited USDC + global soft_max_balance cap. |
The silent filter
Quotes are filtered only when a side's budget reads literally zero at swap time — no deposit on the sell side, or no soft_max_balance headroom on the buy side. A fresh maker has soft_max_balance = 0 everywhere, which makes every buy-side budget 0. The classic cold-start mistake: a maker quoting SOL/USDC with deposited SOL but no soft_max_balance set on the USDC (global) side — sells go up, never fill because the buy-side USDC budget is 0.
5. Install an SDK
cargo add sweetspot-api-client tokio --features tokio/macros,tokio/rt-multi-threadnpm install @superis-labs/sweetspot-client @bufbuild/protobufpip install flint-sdk
# from a checkout:
pip install -e './python[dev]'
make py-gen6. First authenticated call
use std::sync::Arc;
use sweetspot_api_client::api::client::Client;
let client = Client::builder()
.public_endpoint("https://api.superis.exchange:443")
.auth_endpoint("https://auth.api.superis.exchange:443")
.wallet(Arc::new(my_keypair))
.build()
.await?;
let session = client.authenticate().await?;
println!("authenticated as maker_id={}", session.maker_id);If Client::authenticate() returns UNAUTHENTICATED: pubkey not registered as a quoting authority, your pubkey hasn't been added yet — go back to step 3.
7. Verify the program id
Defense in depth. The RPC check confirms the advertised account exists, is executable, and is owned by a Solana BPF loader. To prove it is the Flint program you intended to trade against, compare it with a program id from trusted configuration as well.
use sweetspot_api_client::api::config::verify_program_id;
let cfg = client.refresh_config(None).await?;
verify_program_id("https://api.mainnet-beta.solana.com", &cfg.program_id).await?;Run this once at boot; if either the executable-account check or your trusted program-id comparison fails, refuse to quote until it passes.
8. Pick your path
| Goal | Next page |
|---|---|
| Stream books and fills | Market data |
| Quote and submit fills | Quoting |
| Run or fork a Python maker bot | sweetspot-maker-example |
| Pull historical trades / candles | Historical queries |
| Sign-in flow detail | Auth flow |
