Skip to main content

Funding & Preflight

Authentication success does not prove an institutional integration can trade. An unfunded account can pass HMAC, FIX Logon, FIXP negotiate, connectivity, and schema tests while every bid fails at the risk layer.

This page covers funding in both environments. The preflight further down is the same call in both; only where the balance comes from differs.

Which environment​

SandboxProduction
Base URLhttps://api.sentico-sandbox.xyzhttps://api.sentico-labs.xyz
CollateralMock USDC, booked by the venueReal USDC in the on-chain vault
How you get fundedSelf-service faucet, 100,000 USDC per grantVault deposit, or an operator-provisioned beta bundle
AccessSelf-service, no whitelistWhitelisted private beta
Risk of the testNone; the balance is not realReal collateral you must be prepared to lose

Run conformance in the sandbox first. Use production only for the checks that genuinely require the live venue, and size them accordingly: tiny post-only quotes, cleanup after every test, and a funded account whose balance you are prepared to risk.

Sandbox funding​

The sandbox grants mock USDC on request. The published contract is 100,000 USDC per grant, permitted only while total account equity is below 25,000 USDC, capped at 5 grants per account per rolling 24 hours, idempotent per requestId:

POST /sandbox/v1/faucet
Content-Type: application/json
{
"account": "0xEngineAccount",
"requestId": "ci-run-1043-topup-2",
"amountUsdcMicro": "100000000000",
"issuedAt": 1760000000000,
"expiresAt": 1760000300000,
"signature": "0x..."
}

The first call also materialises the account, so there is no separate provisioning step. The response carries grantsRemaining, grantsTotal and resetAtMs. There are no deposits and no withdrawals in the sandbox, and base assets are acquired by trading rather than by grant. The signed-message grammar, the quota errors and the full sandbox contract are on the Sandbox (launching — see Status) page.

Then run the same funding preflight as production, below.

Production beta model​

Institutional and market-maker testing uses an operator-provisioned, funded beta credential bundle, or a self-funded account: deposit USDC (and the base asset of any spot book you intend to quote) into the vault, wait for the engine credit, and confirm it in the fresh bootstrap read below.

Depositing into the vault​

  • Vault: MultiCollateralVault 0xd1f0fffb736d75fd402121eb14bdc46bfe80ca02 on Arbitrum One. deposit(assetId, amount) and depositWithPermit credit msg.sender only; there is no deposit-for-another-account, so send from the wallet that owns the engine account. assetId is keccak256(abi.encode(token, decimals, chainid)).
  • USDC means native USDC 0xaf88d065e77c8cC2239327C5EDb3A432268e5831, not USDC.e.
  • Engine credit arrives about 15–20 minutes after the on-chain deposit; the listener waits for confirmations. Do not debug signing or risk until the fresh bootstrap shows the balance.
  • Binary and prediction asks sell YES/NO shares and there is no mint-on-fill: run the split action first (1 USDC → 1 YES + 1 NO, fee 1 bp) and size asks below yesFree / noFree.

The bundle should be delivered as JSON. A copyable template lives at scripts/e2e/institutional-beta-bundle.example.json.

The bundle must include:

FieldRequired
environment, apiBaseUrlTarget environment (sandbox, beta) and its API base URL.
ownerWallet20-byte owner wallet.
accountIdHex32-byte trading-account id for control-plane operations.
engineAccount20-byte engine account for balances, signed actions, FIX/FIXP, and streams.
agent.id, agent.type, agent.scopesinstitutional_agent with at least read, trade, cancel, quote, drop_copy.
hmac.apiKeyId, hmac.apiSecret, hmac.apiPassphraseHMAC credential for machine auth and FIX/FIXP.
orderEntry.submitPath, orderEntry.signedBatchFile, orderEntry.idempotencyKeyKnown-good signed batch and submit route for conformance.
expectedFunding.freeUsdcMicroAtLeastMinimum free USDC the first known-good quote requires.
knownGoodQuoteMarket, book, side, price, qty, and time-in-force for a tiny post-only quote.

Minimal shape:

{
"environment": "beta",
"apiBaseUrl": "https://api.sentico-labs.xyz",
"ownerWallet": "0x1111111111111111111111111111111111111111",
"accountIdHex": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"engineAccount": "0x2222222222222222222222222222222222222222",
"agent": {
"id": "agt_...",
"type": "institutional_agent",
"scopes": ["read", "trade", "cancel", "quote", "drop_copy"]
},
"hmac": {
"apiKeyId": "spk_...",
"apiSecret": "sps_...",
"apiPassphrase": "spp_..."
},
"orderEntry": {
"submitPath": "/api/order-entry/binary",
"contentType": "application/x-senticore-order-entry-batch",
"signedBatchFile": "tmp/known-good-bsl-batch.json",
"idempotencyKey": "quote-1-yes-bid-0"
},
"expectedFunding": {
"asset": "USDC",
"freeUsdcMicroAtLeast": "100000000"
},
"knownGoodQuote": {
"kind": "QuoteReplace",
"market": 1,
"book": "YES",
"side": "Bid",
"price": 100000,
"qty": 100000,
"timeInForce": "post_only",
"requiredUsdcMicro": "10000"
}
}

Funding preflight​

Before any quote submit:

GET /api/v1/accounts/:engineAccount/bootstrap?fresh=true
Authorization: Bearer <read token>

Required response properties:

{
"account": "0x2222222222222222222222222222222222222222",
"balanceSource": "matching_engine",
"syncStatus": "synced",
"balances": {
"freeUsdcMicro": "100000000",
"lockedUsdcMicro": "0",
"inOrdersUsdcMicro": "0"
},
"risk": {
"freeUsdcMicro": "100000000"
}
}

Use balances.freeUsdcMicro as the operational check for bid notional. It is not sufficient for every order:

  • A spot ask requires the base token in assetBalances[].free; match the market's base asset and use its native assetDecimals.
  • A binary/outcome ask requires free YES or NO inventory for the selected book.
  • A bid requires free USDC for notional plus fees and configured risk headroom.

If any leg lacks the asset it spends, stop before submitting the batch. Do not infer CKT, TCO, WETH, or USDT availability from the USDC fields.

GET /api/v1/accounts/{engineAccount} is the per-asset view: usdcFree / usdcLocked, assetBalances[{asset, free, locked, assetDecimals}], yesFree / yesLocked / noFree / noLocked per market, openOrders, holds, feeSchedule, nonceFloor / nonceHoles / nonceUsedInWindow, nextNonce and syncStatus. Spot orders also need a notional of at least instrumentConfig.minNotionalMicro from the markets list (1 USDC on current spot markets); a leg below it drops the whole action it belongs to (for a SpotQuoteReplace, all of its legs).

You can run the same check through the external conformance harness:

node scripts/e2e/institutional-conformance-kit.cjs \
--bundle-file tmp/institutional-beta-bundle.json

The harness validates the manifest, applies missing env vars from it, then fails the configured funding gate. expectedFunding.freeUsdcMicroAtLeast only proves the USDC side; configure and verify base/outcome inventory separately for ask legs.

Required notional​

For a bid:

requiredUsdcMicro = floor(priceMicro * qtyMicro / 1_000_000)

Example:

priceMicro = 100000
qtyMicro = 100000
required = 10000 micro USDC

The funded bundle should exceed this by a wide margin because open-order holds, fees, and account-level risk can raise the effective requirement.

What to send support​

When a funded account still rejects with risk:

{
"engineAccount": "0x...",
"accountIdHex": "0x...",
"market": 1,
"book": "YES",
"side": "Bid",
"price": 100000,
"qty": 100000,
"requiredUsdcMicro": "10000",
"bootstrap": {
"balanceSource": "matching_engine",
"syncStatus": "synced",
"balances": {
"freeUsdcMicro": "0",
"lockedUsdcMicro": "0",
"inOrdersUsdcMicro": "0"
},
"risk": {
"freeUsdcMicro": "0"
}
},
"submitResponse": {
"ok": false,
"code": "insufficient_balance",
"error": "..."
}
}

If the bootstrap shows no funding, the fix is provisioning, not client code.