🖥️ API DocsYou can use the Lulo API to fetch a user's deposit information (configured protocols, and latest balances), as well as create deposit and withdrawal transactions for an account.
Authentication
All API requests require a valid API key for authentication, reach out to us to permission an API Key for your team
Copy headers : {
'x-api-key' : process . env . FLEXLEND_API_KEY ,
} ,
GET /account
: list a user account information
The wallet parameter should be added as a header into the GET specified with a header in the request
Copy curl "https://api.flexlend.fi/account" \
--header "x-wallet-pubkey: 6pZiqTT81nKLxMvQay7P6TrRx9NdWG5zbakaZdQoWoUb" \
--header "x-api-key: ${FLEXLEND_API_KEY}"
Copy const response = await fetch ( `https://api.flexlend.fi/account` , {
headers : {
'x-wallet-pubkey' : wallet .toString () ,
'x-api-key' : process . env . FLEXLEND_API_KEY ,
} ,
})
const { data } = await response .json ()
console .log (data)
Response:
Copy {
"totalValue" : 434.28859145610005 ,
"interestEarned" : 19.369569777759786 ,
"realtimeAPY" : 7.69 ,
"settings" : {
"owner" : "6pZiqTT81nKLxMvQay7P6TrRx9NdWG5zbakaZdQoWoUb" ,
"allowedProtocols" : "solend,marginfi,drift,mango" ,
"homebase" : null ,
"minimumRate" : "0" ,
}
Generate APIs
Generate API's abstract the complexity of interacting with the underlying protocols when depositing or withdrawing. These APIs handle all the calculations for certain functionality, and return the resulting transactions as base64 serialized strings. The strings can be unwrapped and signed by the sending wallet (owner
).
Priority fee is required on all generated transactions, and is specified in terms of total SOL lamports. i.e priorityFee=500_000
will add a 0.0005 SOL priority fee to the transaction
The data model for the response is the same for all of the /generate
API's:
Copy {
"transactionMeta" : [
{
"transaction" : "<serialized_base64_transaction>" ,
"protocol" : "kamino" ,
"totalDeposit" : 500
} ,
{
"transaction" : "<serialized_base64_transaction>" ,
"protocol" : "marginfi" ,
"totalDeposit" : 500
}
]
}
POST /generate/account/deposit
Generate a new deposit transaction (or transactions), which the sending wallet can sign and submit.
Copy const request = {
owner : '6pZiqTT81nKLxMvQay7P6TrRx9NdWG5zbakaZdQoWoUb' ,
mintAddress : 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' ,
depositAmount : '500' ,
}
const priority = `?priorityFee=50000`
const response = await fetch ( `https://api.flexlend.fi/generate/account/deposit ${ priority } ` , {
method : 'POST' ,
headers : {
'Accept' : 'application/json' ,
'Content-Type' : 'application/json' ,
'x-wallet-pubkey' : '6pZiqTT81nKLxMvQay7P6TrRx9NdWG5zbakaZdQoWoUb' ,
'x-api-key' : process . env . FLEXLEND_API_KEY ,
} ,
body : JSON .stringify (request) ,
})
const { data: { transactionMeta } } = response .json ()
// wallet can deserialize and sign the transactions
conosle .log ({ transactionMeta })
Copy curl "https://api.flexlend.fi/generate/account/deposit?priorityFee=50000" \
--header "Content-Type: application/json" \
--header "x-wallet-pubkey: 6pZiqTT81nKLxMvQay7P6TrRx9NdWG5zbakaZdQoWoUb" \
--header "x-api-key: ${FLEXLEND_API_KEY}" \
-d '{
"owner": "6pZiqTT81nKLxMvQay7P6TrRx9NdWG5zbakaZdQoWoUb",
"mintAddress": "So11111111111111111111111111111111111111112",
"depositAmount": "50000"
}'
POST /generate/account/withdraw
Generate a withdrawal transaction (or transactions) for an account, which the sending wallet can sign and submit
Copy curl "https://api.flexlend.fi/generate/account/withdraw?priorityFee=50000" \
--header "Content-Type: application/json" \
--header "x-wallet-pubkey: 6pZiqTT81nKLxMvQay7P6TrRx9NdWG5zbakaZdQoWoUb" \
--header "x-api-key: ${FLEXLEND_API_KEY}" \
-d '{
"owner": "6pZiqTT81nKLxMvQay7P6TrRx9NdWG5zbakaZdQoWoUb",
"mintAddress": "So11111111111111111111111111111111111111112",
"withdrawAmount": "5",
"withdrawAll": true
}'
POST /generate/account/update
Generate a transaction that updates the user's settings (protocols, homebase, minimumRate). Returns a single serialized transaction.
Copy curl "https://api.flexlend.fi/generate/account/update?priorityFee=50000" \
--header "Content-Type: application/json" \
--header "x-wallet-pubkey: 6pZiqTT81nKLxMvQay7P6TrRx9NdWG5zbakaZdQoWoUb" \
--header "x-api-key: ${FLEXLEND_API_KEY}" \
-d '{
"owner": "6pZiqTT81nKLxMvQay7P6TrRx9NdWG5zbakaZdQoWoUb",
"allowedProtocols": "marginfi,kamino",
"homebase": null,
"minimumRate": null
}'
Instructions Endpoints
Follows the pattern laid out here: https://station.jup.ag/docs/apis/swap-api#instructions-instead-of-transaction
POST /generate/instructions/deposit
Copy const response = await fetch ( `https://api.flexlend.fi/generate/instructions/deposit?priorityFee=50000` , {
method : 'POST' ,
headers : {
Accept : 'application/json' ,
'Content-Type' : 'application/json' ,
} ,
body : JSON .stringify ({
owner : '6pZiqTT81nKLxMvQay7P6TrRx9NdWG5zbakaZdQoWoUb' ,
mintAddress : 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' ,
depositAmount : '500' ,
allowedProtocols : 'drift,kamino,marginfi,solend,kamino_jlp' ,
isMultiSigTransaction : true
}) ,
})
const instructions = await response .json ()
const {
computeBudgetInstructions , // Required
setupInstructions , // Required
depositInstructions , // Required
addressLookupTableAddresses , // Always one lookup table: 7fxC1WGaJs8fB9xk8LDdMcsyLcD7geKP7uLGL8qoPDTA
targetProtocol , // Destination protocol for the deposit transaction
} = instructions
// follow similar jupiter workflow, with one exception:
// compute and setup instructions are arrays and are required:
const blockhash = ( await connection .getLatestBlockhash ()).blockhash;
const messageV0 = new TransactionMessage ({
payerKey : owner ,
recentBlockhash : blockhash ,
instructions : [
... computeBudgetInstructions .map (deserializeInstruction) ,
... setupInstructions .map (deserializeInstruction) ,
... depositInstructions .map (deserializeInstruction) ,
] ,
}) .compileToV0Message (addressLookupTableAccounts);
const transaction = new VersionedTransaction (messageV0);
POST /generate/instructions/withdraw
If the account was initially deposited using the generate/instructions/deposit
endpoint, the funds will only be in one protocol at a time
Copy const response = await fetch ( `https://api.flexlend.fi/generate/instructions/withdraw?priorityFee=50000` , {
method : 'POST' ,
headers : {
Accept : 'application/json' ,
'Content-Type' : 'application/json' ,
} ,
body : JSON .stringify ({
owner : '6pZiqTT81nKLxMvQay7P6TrRx9NdWG5zbakaZdQoWoUb' ,
mintAddress : 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' ,
withdrawAmount : '500' ,
withdrawAll : true ,
}) ,
})
const instructions = await response .json ()
const {
computeBudgetInstructions , // Required
setupInstructions , // Required
withdrawInstructions , // Required
addressLookupTableAddresses , // Always one lookup table: 7fxC1WGaJs8fB9xk8LDdMcsyLcD7geKP7uLGL8qoP
protocol , // Protocol to withdraw from
} = instructions
// follow similar jupiter workflow, with one exception:
// compute and setup instructions are arrays and are required:
const blockhash = ( await connection .getLatestBlockhash ()).blockhash;
const messageV0 = new TransactionMessage ({
payerKey : owner ,
recentBlockhash : blockhash ,
instructions : [
... computeBudgetInstructions .map (deserializeInstruction) ,
... setupInstructions .map (deserializeInstruction) ,
... withdrawInstructions .map (deserializeInstruction) ,
] ,
}) .compileToV0Message (addressLookupTableAccounts);
const transaction = new VersionedTransaction (messageV0);