Skip to main content

Generate deposit calldata – Earn API

Updated on
Jul 31, 2026

Overview​

Returns one ready-to-sign selfBatchDeposit transaction on the strategy's chain, covering local vault deposits plus per-remote-chain CCTP burns. The matching intent (kind deposit) is written server-side; do not post an intent separately. No auth; no request body (the id is in the path).

Strategy must be pending_setup (top-ups are not supported).

Timing: expiresAt is an advisory ~1h plan-freshness bound. The intent itself has a 30-day TTL; regenerating an unchanged plan within it returns the same intentId, and regenerating after expiry or fulfillment mints a new one. A strategy that has never received a deposit is purged about one hour after it was last touched, taking its intent with it; calling this endpoint refreshes that hour. If signing takes longer than an hour (e.g. a multisig), regenerate at least hourly until the transaction is broadcast.

Approve vault share tokens and USDC before calling: live allowances affect vault selection, and approvalsNeeded reflects what is still missing.

Submit the returned data verbatim (re-encoding breaks intent attribution) and use gasHint as the gas limit (wallet re-estimates can run out of gas).

Endpoint​

POST https://earn-api.quicknode.dev/functions/v1/api/v1/strategies/{id}/calldata/deposit

Authorization​

Include the published apikey header. This endpoint is public and does not require a SIWE signature.

Rate limits​

This operation belongs to the calldata rate-limit bucket. It allows 10 requests per 60 seconds, keyed by strategy+ip. A coarser limit of approximately 30 requests per 60 seconds also applies per IP across deposit, withdrawal, and claim calldata requests.

Parameters​

ParameterLocationTypeRequiredDescription
idpathstringYesStrategy UUID.

Request body​

Deposit calldata request body. Public (no SIWE). The deposit endpoint takes no parameters, so send no body or an empty JSON object ({}).

Example request​

curl --request POST \
--url 'https://earn-api.quicknode.dev/functions/v1/api/v1/strategies/<PENDING_STRATEGY_ID>/calldata/deposit' \
--header 'Accept: application/json' \
--header 'apikey: <EARN_PUBLIC_API_KEY>' \
--header 'Content-Type: application/json' \
--data '{}'

Response​

FieldTypeRequiredDescription
kindstring (deposit)YesIdentifies the response as a deposit calldata plan.
transactionsarray<object>YesExactly one transaction, on the strategy's chain.
approvalsNeededarray<object>YesToken allowances that must be granted before submitting the deposit transaction.
expiresAtstringYes~1h ADVISORY plan-freshness bound. NOT the intent attribution window (the intent carries a 30-day TTL). Regenerate after this passes; regeneration within the intent TTL returns the same `intentId`.
planobjectYesThe deposit allocation plan.
transactions[].chainIdintegerYesChain on which to submit the transaction.
transactions[].tostringYesQuicknode Earn proxy address on `chainId`.
transactions[].datastringYesTransaction calldata. Submit it verbatim.
transactions[].valuestringYesNative-token value. Always `"0"`.
transactions[].intentIdstringYesIntent UUID used to track the transaction.
transactions[].kindstring (deposit)YesTransaction intent kind.
transactions[].descriptionstringYesHuman-readable transaction summary.
transactions[].gasHintstring | nullYesRecommended gas limit, or `null` when it cannot be estimated.
transactions[].gasHintReasonstringNo`approvals_required` or `estimation_failed` when `gasHint` is `null`.
approvalsNeeded[].chainIdintegerYesChain where approval is required.
approvalsNeeded[].tokenstringYesToken contract requiring an allowance.
approvalsNeeded[].spenderstringYesQuicknode Earn proxy address.
approvalsNeeded[].currentAllowancestringYesCurrent allowance in token base units.
approvalsNeeded[].requiredAllowancestringYesRequired allowance in token base units.
approvalsNeeded[].txobjectYesReady-to-sign token approval transaction.
approvalsNeeded[].tx.tostringYesToken contract receiving the approval call.
approvalsNeeded[].tx.datastringYesABI-encoded approval calldata.
approvalsNeeded[].tx.valuestringYesNative-token value, normally `"0"`.
plan.totalUsdcstringYesTotal allocated USDC as a six-decimal base-unit string.
plan.vaultsarray<string>YesLocal-chain vault addresses.
plan.amountsarray<string>YesBase-unit amounts aligned with `plan.vaults`.
plan.burnsarray<object>YesCombined CCTP burns for remote chains.
plan.burns[].destDomainintegerYesCCTP destination domain.
plan.burns[].mintRecipientstringYesBytes32-padded mint recipient.
plan.burns[].destinationCallerstringYesBytes32-padded destination caller.
plan.burns[].amountstringYesBurn amount in USDC base units.
plan.burns[].maxFeestringYesMaximum CCTP fee in base units.
plan.burns[].minFinalityThresholdintegerYesMinimum CCTP finality threshold.
plan.burnVaultBreakdownarray<array<object>>YesDestination vault allocations aligned with `plan.burns`.
plan.burnVaultBreakdown[][].vaultstringYesDestination vault address.
plan.burnVaultBreakdown[][].amountstringYesVault allocation in USDC base units.
plan.burnVaultBreakdown[][].namestringYesDestination vault name.
plan.burnVaultBreakdown[][].apynumberYesDestination vault APY percentage.
plan.apysobjectYesMap of vault keys to APY percentages.
plan.vaultNamesobjectYesMap of vault keys to vault names.
plan.chainIdsobjectYesMap of vault keys to chain IDs.

Example response​

{
"kind": "deposit",
"transactions": [
{
"chainId": 8453,
"to": "0x48b415841165304f7EfaA7D5dD5FC65cc7B4bd8e",
"data": "0x5a6b7c8d0000000000000000000000000000000000000000000000000000000000000060",
"value": "0",
"intentId": "7f3a1c2b-0000-4000-8000-000000000abc",
"kind": "deposit",
"description": "Deposit $1000 into 2 vault(s), bridging to 1 chain(s)",
"gasHint": "480000"
}
],
"approvalsNeeded": [],
"plan": {
"totalUsdc": "1000000000",
"vaults": ["0x616a4e1db48e22028f6bbf20444cd3b8e3273738"],
"amounts": ["600000000"],
"burns": [
{
"destDomain": 3,
"mintRecipient": "0x00000000000000000000000048b415841165304f7efaa7d5dd5fc65cc7b4bd8e",
"destinationCaller": "0x00000000000000000000000048b415841165304f7efaa7d5dd5fc65cc7b4bd8e",
"amount": "400000000",
"maxFee": "0",
"minFinalityThreshold": 2000
}
],
"burnVaultBreakdown": [
[
{
"vault": "0x1a996cb54bb95462040408c06122d45d6cdb6096",
"amount": "400000000",
"name": "Gauntlet USDC Core",
"apy": 5.117
}
]
],
"apys": {
"8453:0x616a4e1db48e22028f6bbf20444cd3b8e3273738": 6.482,
"42161:0x1a996cb54bb95462040408c06122d45d6cdb6096": 5.117
},
"vaultNames": {
"8453:0x616a4e1db48e22028f6bbf20444cd3b8e3273738": "Seamless USDC Vault",
"42161:0x1a996cb54bb95462040408c06122d45d6cdb6096": "Gauntlet USDC Core"
},
"chainIds": {
"8453:0x616a4e1db48e22028f6bbf20444cd3b8e3273738": 8453,
"42161:0x1a996cb54bb95462040408c06122d45d6cdb6096": 42161
}
},
"expiresAt": "2026-07-07T19:00:00.000Z"
}

HTTP responses​

StatusDescription
200One deposit transaction, approvals needed, plan transparency, and an advisory expiry.
400One of: the strategy is not `pending_setup` (`invalid_state`); no eligible vaults (`no_eligible_vaults`); gas estimation failed (`gas_estimation_failed`, the tx would revert, usually unfunded or unapproved); or a malformed JSON body (`invalid_request`).
404Resource not found.
429Rate limit exceeded. `Retry-After` (seconds) tells you when to retry. Reads, feedback, and push writes are keyed per IP; create/update/delete are keyed per wallet+IP; deposit/withdraw/claim calldata is keyed per strategy+IP.
500Internal error, or `burn_route_unavailable` when a required remote chain has no CCTP burn route configured.
503The hide list could not be loaded (`hide_lookup_failed`, fails closed).
OpenAPI source

This page is based on operation depositCalldata in the Earn OpenAPI 3.1 specification.