{"openapi":"3.1.0","info":{"title":"FireStrat partner API","version":"1.0.0","description":"Get quotes and unsigned transactions for frUSD, frBTC and frSPY deposits and withdrawals, and read positions and transaction status. The API returns unsigned transactions. The user's own wallet signs and sends them. We never hold a user key."},"servers":[{"url":"https://api.firestrat.xyz","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Tokens","description":"The tokens and their status."},{"name":"Actions","description":"Quote and build a deposit or a withdrawal."},{"name":"Positions","description":"The balances of a wallet."},{"name":"Transactions","description":"The status and receipt of a transaction."},{"name":"Meta","description":"This file."}],"paths":{"/v1/tokens":{"get":{"operationId":"getTokens","tags":["Tokens"],"summary":"List the tokens","description":"Public: no key is needed. The limit is 60 requests a minute for each IP. When a valid key is sent, the request also counts as that partner's usage.","security":[{},{"bearerAuth":[]}],"responses":{"200":{"description":"The tokens.","headers":{"Cache-Control":{"description":"Cloudflare and browsers keep the response for 30 seconds.","schema":{"type":"string"},"example":"public, max-age=30, s-maxage=30"},"Access-Control-Allow-Origin":{"description":"Any origin can read this response.","schema":{"type":"string"},"example":"*"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokensResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/v1/quote":{"post":{"operationId":"quote","tags":["Actions"],"summary":"Quote a deposit or a withdrawal","description":"Returns the amounts for the action. No transaction is returned. When frBTC needs account setup first, `steps` is 2, `expectedOut` and `minOut` are null, and the warning `setup_required` is set.","requestBody":{"required":true,"description":"The action. The body is at most 4096 bytes. Unknown fields are refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActionRequest"}}}},"responses":{"200":{"description":"The quote.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/v1/build":{"post":{"operationId":"build","tags":["Actions"],"summary":"Build the next unsigned transaction of an action","description":"Returns the next step as an unsigned Solana transaction. The wallet of the user is the fee payer and the only signer. The server simulates the transaction before it returns it. Call this endpoint again only after the step before it is confirmed, or the user can deposit twice. A frBTC withdrawal that takes USDG from the wallet needs `acceptDebits: true`.","parameters":[{"name":"includeInstructions","in":"query","required":false,"description":"Use `true` to include the instruction plan for this step. If supplied, the parameter must occur once and its value must be `true` or `false`.","schema":{"type":"boolean","default":false}}],"requestBody":{"required":true,"description":"The action. The body is at most 4096 bytes. Unknown fields are refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActionRequest"}}}},"responses":{"200":{"description":"The next step.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/v1/positions/{wallet}":{"get":{"operationId":"getPositions","tags":["Positions"],"summary":"Read the positions of a wallet","description":"Reads the current balances only. It never reads the history of the wallet.","parameters":[{"name":"wallet","in":"path","required":true,"description":"The wallet address, base58.","schema":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"}}],"responses":{"200":{"description":"The positions.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/v1/transactions/{signature}":{"get":{"operationId":"getTransaction","tags":["Transactions"],"summary":"Read the status of a transaction","description":"Returns the status and the current block height. When the transaction is confirmed or finalized and changes exactly one share token, the response also has a receipt.","parameters":[{"name":"signature","in":"path","required":true,"description":"The transaction signature, base58.","schema":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{64,88}$"}}],"responses":{"200":{"description":"The status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionStatus"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/v1/openapi.json":{"get":{"operationId":"getOpenApi","tags":["Meta"],"summary":"Read this file","description":"Public: no key is needed. The limit is 60 requests a minute for each IP.","security":[],"responses":{"200":{"description":"The OpenAPI 3.1 file for version 1.","headers":{"Cache-Control":{"description":"Cloudflare and browsers keep the response for 5 minutes.","schema":{"type":"string"},"example":"public, max-age=300"}},"content":{"application/json":{"schema":{"type":"object"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"The API key, sent as `Authorization: Bearer fsk_live_...`. It is the only accepted form. A key with no allowed origins is for servers only and is refused when a request has an `Origin` header."}},"responses":{"BadRequest":{"description":"A bad token, action, asset, address, amount, slippage or query parameter, or a token that is not available yet. The code is `invalid_request`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"Unauthorized":{"description":"The key is missing, unknown or revoked. The code is `invalid_key` or `revoked_key`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"Forbidden":{"description":"A browser origin that is not in the key's list. The code is `origin_not_allowed`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"NotFound":{"description":"Unknown path, wrong host, or the API is off. The code is `not_found`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"Conflict":{"description":"The action is not possible now. The code is `debit_not_accepted`, `deposits_paused`, `pending_exit` or `full_exit_not_supported`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"Unprocessable":{"description":"The action fails a check. The code is `amount_too_small`, `insufficient_balance`, `insufficient_sol`, `withdrawal_needs_usdg` or `simulation_failed`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"RateLimited":{"description":"A limit is reached. The code is `rate_limited`. Retry after the time in `Retry-After`.","headers":{"Retry-After":{"description":"The number of seconds to wait.","schema":{"type":"string","pattern":"^[0-9]+$"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"InternalError":{"description":"Any other error. The message is generic. The code is `internal`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"Unavailable":{"description":"The chain or an upstream read failed. The code is `chain_unreadable` or `upstream_unavailable`. The same request can succeed later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"schemas":{"TokenId":{"type":"string","enum":["frUSD","frBTC","frSPY"],"description":"A token of the protocol."},"ErrorCode":{"type":"string","enum":["invalid_key","revoked_key","origin_not_allowed","not_found","rate_limited","invalid_request","amount_too_small","insufficient_balance","insufficient_sol","withdrawal_needs_usdg","debit_not_accepted","deposits_paused","pending_exit","full_exit_not_supported","simulation_failed","chain_unreadable","upstream_unavailable","internal"],"description":"The cause of an error. `rate_limited`, `chain_unreadable` and `upstream_unavailable` are retryable."},"ActionRequest":{"type":"object","additionalProperties":false,"required":["token","action","wallet","asset","amount"],"properties":{"token":{"$ref":"#/components/schemas/TokenId"},"action":{"type":"string","enum":["deposit","withdraw"]},"wallet":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"The wallet of the user, base58. It is the fee payer and the only signer."},"asset":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"A mint from the `deposit.assets` or `withdraw.assets` list of the token in `GET /v1/tokens`."},"amount":{"type":"string","pattern":"^(0|[1-9][0-9]{0,19})$","description":"A raw base-unit amount, more than 0 and at most 2^64 - 1. For a deposit it is in the deposit asset. For a withdrawal it is in the token (shares)."},"slippageBps":{"type":"integer","minimum":0,"maximum":500,"default":50,"description":"The slippage in basis points."},"acceptDebits":{"type":"boolean","description":"frBTC withdrawal only. Set it to true after you show the user the USDG that the withdrawal takes from the wallet."}}},"Quote":{"type":"object","required":["token","action","wallet","amountIn","mintIn","expectedOut","minOut","mintOut","otherOutputs","debits","slippageBps","steps","warnings"],"properties":{"token":{"$ref":"#/components/schemas/TokenId"},"action":{"type":"string","enum":["deposit","withdraw"]},"wallet":{"type":"string","description":"The wallet address, base58."},"amountIn":{"type":"string","pattern":"^(0|[1-9][0-9]{0,19})$","description":"The input amount, raw base units."},"mintIn":{"type":"string","description":"The mint of the input asset."},"expectedOut":{"type":["string","null"],"pattern":"^(0|[1-9][0-9]{0,19})$","description":"The expected output, raw base units. It is null only with the warning `setup_required`."},"minOut":{"type":["string","null"],"pattern":"^(0|[1-9][0-9]{0,19})$","description":"The minimum output after slippage, raw base units."},"mintOut":{"type":"string","description":"The mint of the output asset."},"otherOutputs":{"type":"array","description":"Other assets that the action returns. A frBTC withdrawal can return USDG and PT-ONYC.","items":{"type":"object","required":["mint","expected","min"],"properties":{"mint":{"type":"string","description":"Mint address, base58."},"expected":{"type":"string","pattern":"^(0|[1-9][0-9]{0,19})$","description":"The expected amount, raw base units."},"min":{"type":"string","pattern":"^(0|[1-9][0-9]{0,19})$","description":"The minimum amount, raw base units."}}}},"debits":{"type":"array","description":"Assets that the action takes from the wallet. A frBTC withdrawal can take USDG.","items":{"type":"object","required":["mint","max"],"properties":{"mint":{"type":"string","description":"Mint address, base58."},"max":{"type":"string","pattern":"^(0|[1-9][0-9]{0,19})$","description":"The maximum amount, raw base units."}}}},"slippageBps":{"type":"integer","minimum":0,"maximum":500},"steps":{"type":"integer","enum":[1,2],"description":"The signatures from now. It is 2 only when frBTC needs account setup first."},"warnings":{"type":"array","items":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}},"BuildResponse":{"type":"object","required":["step","transaction","lastValidBlockHeight","quote","simulation"],"properties":{"step":{"type":"object","required":["kind","label","remaining"],"properties":{"kind":{"type":"string","enum":["setup","action"]},"label":{"type":"string","description":"A short text for the user interface."},"remaining":{"type":"integer","enum":[1,2],"description":"The signatures from now, this one included."}}},"transaction":{"type":"string","description":"The unsigned Solana transaction, base64."},"lastValidBlockHeight":{"type":"string","pattern":"^(0|[1-9][0-9]{0,19})$","description":"The last block height at which the transaction can land."},"quote":{"$ref":"#/components/schemas/Quote"},"simulation":{"type":"object","required":["unitsConsumed"],"properties":{"unitsConsumed":{"type":"integer","minimum":0}}},"instructionPlan":{"$ref":"#/components/schemas/InstructionPlan"}}},"InstructionPlan":{"type":"object","description":"Present when includeInstructions is true. The ordered input to the compiler for the simulated step. Preserve the order and grouping of the instructions. For an atomic version 1 product step, the compiler moves the compute budget into the message header and restricts which instructions can precede the product instruction. Simulate a modified transaction before signing it.","required":["messageVersion","feePayer","lookupTableAddresses","instructions"],"properties":{"messageVersion":{"type":"integer","enum":[0,1],"description":"The effective Solana message version of the returned transaction."},"feePayer":{"type":"string","description":"Fee payer address, base58."},"lookupTableAddresses":{"type":"array","description":"Address lookup tables for compilation, base58. Empty for message version 1.","items":{"type":"string"}},"instructions":{"type":"array","items":{"type":"object","required":["programId","accounts","data"],"properties":{"programId":{"type":"string","description":"Program address, base58."},"accounts":{"type":"array","description":"Account metadata in instruction order.","items":{"type":"object","required":["pubkey","isSigner","isWritable"],"properties":{"pubkey":{"type":"string","description":"Account address, base58."},"isSigner":{"type":"boolean"},"isWritable":{"type":"boolean"}}}},"data":{"type":"string","pattern":"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$","description":"Instruction data, standard base64. Empty when the instruction has no data."}}}}}},"AssetInfo":{"type":"object","required":["mint","symbol","decimals","minAmount"],"properties":{"mint":{"type":"string","description":"Mint address, base58."},"symbol":{"type":"string"},"decimals":{"type":"integer","minimum":0},"minAmount":{"type":"string","pattern":"^(0|[1-9][0-9]{0,19})$","description":"The smallest amount that the API accepts, raw base units."}}},"TokenInfo":{"type":"object","required":["token","mint","decimals","status","statusReason","sharePrice","apy","deposit","withdraw"],"properties":{"token":{"$ref":"#/components/schemas/TokenId"},"mint":{"type":"string","description":"The mint of the token."},"decimals":{"type":"integer","minimum":0},"status":{"type":"string","enum":["open","deposits_paused"]},"statusReason":{"type":["string","null"],"description":"The same text that the site shows."},"sharePrice":{"type":"object","required":["underlyingMint","underlying","usd"],"properties":{"underlyingMint":{"type":"string","description":"USDC for frUSD, xBTC for frBTC, SPYx for frSPY."},"underlying":{"type":["string","null"],"description":"A decimal string: the underlying amount for 1 token."},"usd":{"type":["string","null"],"description":"A decimal string: the USD value of 1 token."}}},"apy":{"type":"object","description":"Percent, on the basis of the site headline.","required":["now","days30"],"properties":{"now":{"type":["number","null"]},"days30":{"type":["number","null"]}}},"deposit":{"type":"object","required":["assets"],"properties":{"assets":{"type":"array","items":{"$ref":"#/components/schemas/AssetInfo"}}}},"withdraw":{"type":"object","required":["assets"],"properties":{"assets":{"type":"array","items":{"$ref":"#/components/schemas/AssetInfo"}}}}}},"TokensResponse":{"type":"object","required":["tokens"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/TokenInfo"}}}},"PositionsResponse":{"type":"object","required":["wallet","positions"],"properties":{"wallet":{"type":"string","description":"The wallet address, base58."},"positions":{"type":"array","items":{"type":"object","required":["token","mint","balance","decimals","value"],"properties":{"token":{"$ref":"#/components/schemas/TokenId"},"mint":{"type":"string","description":"The mint of the token."},"balance":{"type":"string","pattern":"^(0|[1-9][0-9]{0,19})$","description":"The balance, raw base units."},"decimals":{"type":"integer","minimum":0},"value":{"type":"object","required":["underlyingMint","underlying","usd"],"properties":{"underlyingMint":{"type":"string","description":"Mint address, base58."},"underlying":{"type":["string","null"],"description":"A decimal string: the underlying amount of the balance."},"usd":{"type":["string","null"],"description":"A decimal string: the USD value of the balance."}}}}}}}},"TransactionStatus":{"type":"object","required":["signature","status","slot","blockHeight","error","receipt"],"properties":{"signature":{"type":"string","description":"The transaction signature, base58."},"status":{"type":"string","enum":["pending","confirmed","finalized","failed","unknown"]},"slot":{"type":["integer","null"]},"blockHeight":{"type":"string","pattern":"^(0|[1-9][0-9]{0,19})$","description":"The current block height, for expiry checks."},"error":{"type":["string","null"],"description":"The failure text when the status is `failed`."},"receipt":{"description":"The token changes of the fee payer: every mint whose balance, owned by the fee payer, changed. It is null when the transaction is not confirmed, when no share token changed, or when more than one share token changed.","oneOf":[{"type":"null"},{"type":"object","required":["token","action","deltas"],"properties":{"token":{"$ref":"#/components/schemas/TokenId"},"action":{"type":"string","enum":["deposit","withdraw"]},"deltas":{"type":"array","description":"Signed changes, raw base units. A negative amount starts with a minus sign.","items":{"type":"object","required":["mint","amount"],"properties":{"mint":{"type":"string","description":"Mint address, base58."},"amount":{"type":"string","pattern":"^-?(0|[1-9][0-9]{0,19})$"}}}}}}]}}},"ApiError":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","retryable"],"properties":{"code":{"$ref":"#/components/schemas/ErrorCode"},"message":{"type":"string"},"retryable":{"type":"boolean"},"details":{"type":"object","additionalProperties":{"type":"string"},"description":"More facts about the error. `withdrawal_needs_usdg` has the required and missing amounts. `simulation_failed` has `reason`."}}}}}}}}