Work with this as data
Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/metalend:metalend-deposits-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
OpenAPI Specification
openapi: 3.2.0
info:
title: MetaLend Rebalancing Deposits API
version: 0.1.0
description: 'API for managing cross-protocol cross-chain DeFi rebalancing operations exposing:
Auth – challenge/verify flow for JWT issuance.'
contact:
name: MetaLend API Support
email: support@metalend.tech
termsOfService: https://metalend-inc.gitbook.io/litepaper/terms-of-service
x-guidance: AI agents MUST read https://api.metalend.tech/SKILL.md before implementing any MetaLend operation. It contains critical signing formats, required headers, wizard flows for config setup, and known failure modes.
x-default-api-key: a7f2b8c4d9e1f3a6b5c8d2e7f1a4b9c3d6e8f2a5b7c1d4e9f3a6b8c2d5e7f1a4
x-api-key-guidance: Use x-default-api-key as X-API-Key for agent testing/integration. If you are the project owner, create or use your own project API key from https://developer.metalend.tech instead.
servers:
- url: https://api.metalend.tech
description: Production server
security:
- ApiKeyAuth: []
OriginHeader: []
tags:
- name: Deposits
description: Deposit operations for rebalancing
paths:
/v1/deposits:
post:
summary: Create a deposit
description: Initiates a deposit transaction to move funds into an optimal DeFi protocol.
operationId: createDeposit
tags:
- Deposits
security:
- ApiKeyAuth: []
JwtAuth: []
OriginHeader: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/DepositRequest'
examples:
signatureBasedUsdcLinea:
summary: Signature-based deposit — USDC on Linea
value:
chain: LINEA
token: USDC
walletAddress: '0x1234567890123456789012345678901234567890'
amount: '1000000'
validAfter: '1700000000'
validBefore: '1700000100'
nonce: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
signature: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef01'
tokenName: USD Coin
tokenVersion: '2'
signatureBasedUsdcEth:
summary: Signature-based deposit — USDC on Ethereum
value:
chain: ETHEREUM
token: USDC
walletAddress: '0x1234567890123456789012345678901234567890'
amount: '5000000'
validAfter: '1700000000'
validBefore: '1700000100'
nonce: '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890'
signature: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef01'
tokenName: USD Coin
tokenVersion: '2'
approvalBasedUsdtEthereum:
summary: Approval-based deposit — USDT on Ethereum
value:
chain: ETHEREUM
token: USDT
walletAddress: '0x1234567890123456789012345678901234567890'
amount: '1000000'
approvalBasedUsdcBase:
summary: Approval-based deposit — USDC on Base
value:
chain: BASE
token: USDC
walletAddress: '0x1234567890123456789012345678901234567890'
amount: '2000000'
approvalBasedUsdcArbitrum:
summary: Approval-based deposit — USDC on Arbitrum
value:
chain: ARBITRUM
token: USDC
walletAddress: '0x1234567890123456789012345678901234567890'
amount: '3000000'
responses:
'201':
description: Deposit initiated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/DepositResponse'
'400':
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
examples:
walletAddressBlank:
$ref: '#/components/examples/WalletAddressBlank'
invalidAddressFormat:
$ref: '#/components/examples/InvalidAddressFormat'
invalidAddressCheckSum:
$ref: '#/components/examples/InvalidAddressCheckSum'
signatureNotAllowed:
$ref: '#/components/examples/SignatureNotAllowed'
invalidTokenNameOrVersion:
$ref: '#/components/examples/InvalidTokenNameOrVersion'
partialSignatureFields:
$ref: '#/components/examples/PartialSignatureFields'
tokenNotSupported:
$ref: '#/components/examples/TokenNotSupported'
chainBlank:
$ref: '#/components/examples/ChainBlank'
chainNotSupported:
$ref: '#/components/examples/ChainNotSupported'
amountTooLow:
$ref: '#/components/examples/AmountTooLow'
invalidTimestampBeforeGreaterThanAfter:
$ref: '#/components/examples/InvalidTimestampBeforeGreaterThanAfter'
invalidTimestampAfterMustBeInPastOrNow:
$ref: '#/components/examples/InvalidTimestampAfterMustBeInPastOrNow'
invalidTimestampBeforeMustBeInFuture:
$ref: '#/components/examples/InvalidTimestampBeforeMustBeInFuture'
invalidTimestampBeforeMustBeAtMostOneMinuteInFuture:
$ref: '#/components/examples/InvalidTimestampBeforeMustBeAtMostOneMinuteInFuture'
insufficientApproval:
$ref: '#/components/examples/InsufficientApproval'
tokenNotSupportedOnChain:
$ref: '#/components/examples/TokenNotSupportedOnChain'
insufficientBalance:
$ref: '#/components/examples/InsufficientBalance'
depositInvalidSignature:
$ref: '#/components/examples/DepositInvalidSignature'
'401':
$ref: '#/components/responses/UnauthorizedNoHeader'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/RateLimitExceeded'
'500':
$ref: '#/components/responses/InternalError'
'503':
description: Service unavailable — deposits paused (maintenance)
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
examples:
depositsPaused:
$ref: '#/components/examples/DepositsPaused'
x-agentcash-auth:
mode: free
/v1/deposits/{trackingId}:
get:
summary: Get deposit status
description: 'Retrieves the current status and details of a deposit transaction using its unique tracking ID.
This endpoint allows you to monitor the progress of a deposit from initiation to completion.
The tracking ID is returned when you create a deposit in UUID format.
Please be aware that if you see failed state, it can be also due to high gas fees, max allowed is 1 USD in gas fees, otherwise it will fail.
**Status Values** (returned in `status`):
- `PROCESSING`: Deposit is queued or being handled on the source chain.
- `BRIDGING` (cross-chain only): Source-side funds movement succeeded and is bridging to the destination chain. Same-chain deposits go straight to final `SUCCESS` or `FAILED` status.
- `SUCCESS`: Deposit has been successfully completed and funds are in the protocol.
- `FAILED`: Deposit transaction has failed (e.g., insufficient gas, transaction reverted).
- `EMERGENCY_WITHDRAW`: Destination-side deposit could not complete; funds were recovered via emergency withdrawal.
The API only exposes the five values above. Any other internal persistence state is mapped to `PROCESSING` for this response until the flow resolves.
**Response Details:**
When successful, the response includes:
- Current deposit status ("SUCCESS")
- Target protocol name (e.g., "Aave", "Morpho", "Euler") where funds were deposited
- Pool/vault contract address receiving the funds
- Blockchain network where the deposit occurred
**Use Cases:**
- Poll this endpoint to track deposit progress after creation
- Verify successful completion before proceeding with other operations
- Display real-time status updates to users in your application
**Note:** If you receive a error code, the tracking ID is probably invalid or no deposit exists for that ID.
**Rate limiting**: 1 request per 3 seconds per client IP. Excess requests receive HTTP `429` with `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers (see `RateLimitExceeded` response).'
operationId: getDepositStatus
tags:
- Deposits
security:
- ApiKeyAuth: []
OriginHeader: []
parameters:
- name: trackingId
in: path
required: true
description: Tracking ID (UUID) returned from deposit creation
schema:
type: string
example: 550e8400-e29b-41d4-a716-446655440000
responses:
'200':
description: Deposit status retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/DepositStatusResponse'
examples:
processing:
summary: Deposit picked up, waiting for on-chain execution
value:
status: PROCESSING
protocol: null
pool: null
chain: base
bridging:
summary: Cross-chain deposit — source tx done, bridge in progress
description: Details of the target pool, protocol and chain.
value:
status: BRIDGING
protocol: Aave
pool: '0xc47b8C00b0f69a36fa203Ffeac0334874574a8Ac'
chain: base
success:
summary: Deposit completed successfully
value:
status: SUCCESS
protocol: Aave
pool: '0xc47b8C00b0f69a36fa203Ffeac0334874574a8Ac'
chain: base
failed:
summary: Deposit failed
value:
status: FAILED
protocol: null
pool: null
chain: base
emergencyWithdraw:
summary: Destination deposit failed — funds emergency-withdrawn
value:
status: EMERGENCY_WITHDRAW
protocol: Aave
pool: '0xc47b8C00b0f69a36fa203Ffeac0334874574a8Ac'
chain: base
'400':
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
examples:
missingTrackingId:
$ref: '#/components/examples/MissingTrackingId'
invalidTrackingId:
$ref: '#/components/examples/InvalidTrackingId'
'401':
$ref: '#/components/responses/UnauthorizedNoHeader'
'429':
$ref: '#/components/responses/RateLimitExceeded'
'404':
description: Tracking ID not found
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
examples:
trackingIdNotFound:
$ref: '#/components/examples/TrackingIdNotFound'
'500':
$ref: '#/components/responses/InternalError'
x-agentcash-auth:
mode: free
components:
examples:
InvalidTimestampBeforeGreaterThanAfter:
summary: Invalid timestamp before greater than after
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: INVALID_TIMESTAMPS
message: 'Invalid timestamps: validBefore must be greater than validAfter'
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
UnauthorizedNoHeader:
summary: No authorization header
value:
code: AUTHENTICATION_FAILED
internalCode: NO_AUTH_INFO
message: No authentication information provided
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
WalletAddressBlank:
summary: Wallet address blank
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: BLANK_ADDRESS
message: Wallet address cannot be blank
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
TokenNotSupported:
summary: Token not supported
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: TOKEN_NOT_SUPPORTED
message: 'Token ''RLUSD'' is not supported. Supported tokens: USDC, MUSD, USDT'
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
TrackingIdNotFound:
summary: Tracking ID not found
value:
code: NOT_FOUND_ERROR
internalCode: RESOURCE_NOT_FOUND
message: deposits/{trackingId} with identifier '0x1234...abcdef01' not found
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
InvalidTimestampBeforeMustBeInFuture:
summary: Invalid timestamp before must be future
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: INVALID_TIMESTAMPS
message: 'Invalid timestamps: validBefore must be in the future'
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
InvalidTimestampAfterMustBeInPastOrNow:
summary: Invalid timestamp after must be in past or now
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: INVALID_TIMESTAMPS
message: 'Invalid timestamps: validAfter must be in the past or now'
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
InsufficientBalance:
summary: Insufficient wallet balance
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: INSUFFICIENT_BALANCE
message: Insufficient balance. Available balance is 500000 raw units, but request required amount is 1000000 raw units.
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
PartialSignatureFields:
summary: Partial signature fields provided
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: ILLEGAL_ARGUMENT
message: 'Illegal argument: Either provide all or none of the signature-related fields: validAfter, validBefore, nonce, signature, tokenName, tokenVersion'
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
InvalidTrackingId:
summary: Invalid tracking ID
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: INVALID_TRACKING_ID
message: 'Invalid tracking ID format: ''$trackingId'''
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
SignatureNotAllowed:
summary: Token not supported for signature-based deposits
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: TOKEN_NOT_SUPPORTED_FOR_SIGNATURE_BASED_DEPOSIT
message: 'Token ''USDT'' is not supported for signature-based deposits. Supported tokens: USDC, MUSD'
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
DepositsPaused:
summary: Deposits temporarily paused (maintenance)
value:
code: SERVICE_UNAVAILABLE
internalCode: DEPOSITS_PAUSED
message: Deposits are temporarily paused
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
InsufficientApproval:
summary: Token approval does not match the required amount
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: APPROVAL_VALIDATION_ERROR
message: 'Approval validation error: Token approval amount 0 does not match required amount 1000000'
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
DepositInvalidSignature:
summary: Invalid deposit signature
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: INVALID_SIGNATURE
message: 'Invalid signature for address ''0x1234567890123456789012345678901234567890'': Deposit signature must be 132 characters long and start with ''0x'''
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
TokenNotSupportedOnChain:
summary: Token not supported on chain
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: TOKEN_NOT_SUPPORTED_ON_CHAIN
message: 'Token ''RLUSD'' is not supported on chain ''linea''. Supported tokens: USDC, MUSD, USDT'
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
AmountTooLow:
summary: Amount too low for deposit
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: AMOUNT_TOO_LOW
message: Amount is too low. Minimum required amount is 100000 raw units for operation 'DEPOSIT' on chain 'linea'
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
InvalidAddressFormat:
summary: Invalid address format
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: INVALID_ADDRESS_FORMAT
message: 'Invalid address format. Expected: 0x followed by 40 hexadecimal characters.'
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
MissingTrackingId:
summary: Missing tracking ID
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: BLANK_TRACKING_ID
message: Tracking ID cannot be blank
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
InvalidTimestampBeforeMustBeAtMostOneMinuteInFuture:
summary: Invalid timestamp before too far
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: INVALID_TIMESTAMPS
message: 'Invalid timestamps: validBefore must be at most 1 minute in the future'
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
InvalidTokenNameOrVersion:
summary: Invalid token name or version for EIP-712
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: INVALID_TOKEN_NAME_OR_VERSION
message: 'Invalid token name or version for EIP-712 domain: Expected name: ''USD Coin'', version: ''2''. Provided name: ''USDC'', version: ''1''.'
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
ChainBlank:
summary: Chain blank
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: CHAIN_BLANK
message: Chain cannot be blank
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
ChainNotSupported:
summary: Chain not supported
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: CHAIN_NOT_SUPPORTED
message: 'Chain ''STX'' is not supported. Supported chains: eth, base, polygon, arbitrum, optimism, avax, linea'
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
InvalidAddressCheckSum:
summary: Invalid address checksum
value:
code: ILLEGAL_ARGUMENT_ERROR
internalCode: INVALID_ADDRESS_CHECKSUM
message: Invalid Ethereum address checksum. Please ensure the address is properly checksummed (EIP-55)
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
schemas:
ApiError:
type: object
required:
- code
- internalCode
- message
properties:
code:
type: string
description: Error category identifier
internalCode:
type: string
description: More specific error identifier
message:
type: string
description: Human-readable error message
requestId:
type: string
format: uuid
description: Unique request identifier for tracking
retryAfterSeconds:
type: integer
description: Seconds to wait before retrying (for rate limiting)
DepositRequest:
type: object
required:
- chain
- token
- walletAddress
- amount
properties:
chain:
type: string
enum:
- ETHEREUM
- BASE
- POLYGON
- ARBITRUM
- OPTIMISM
- AVALANCHE
- LINEA
description: 'The blockchain network for this deposit. IMPORTANT: Do NOT derive this from wagmi''s chain.name or chain.network — those use different naming conventions. Always use PoolBalance.chain from GET /v1/balances which is already in the correct API format. For chain switching before the on-chain approve() call, use PoolBalance.chainId (integer EVM chain ID) with switchChain({ chainId }).
If you must map from wagmi/viem chainId to this field, use: - chainId 1 → "ETHEREUM" - chainId 8453 → "BASE" - chainId 137 → "POLYGON" - chainId 42161 → "ARBITRUM" - chainId 10 → "OPTIMISM" - chainId 43114 → "AVALANCHE" - chainId 59144 → "LINEA"
'
token:
type: string
enum:
- USDC
- MUSD
- USDT
- RLUSD
description: Token symbol to configure (must be uppercase)
walletAddress:
type: string
pattern: ^0x[a-fA-F0-9]{40}$
description: User's Ethereum wallet address (must be checksummed per EIP-55)
amount:
type: string
description: Amount in token's smallest unit (minimum 0.1 to cover gas fees)
example: '1000000'
validAfter:
type: string
description: Unix timestamp after which signature is valid (required for signature based approvals)
example: '1700000000'
validBefore:
type: string
description: Unix timestamp before which signature is valid (required for signature based approvals, max 1 min in future, > validAfter)
example: '1700000100'
nonce:
type: string
pattern: ^0x[a-fA-F0-9]{64}$
description: Unique nonce for signature (required for signature based approvals)
signature:
type: string
pattern: ^0x[a-fA-F0-9]{130}$
description: EIP-712 signature for authorization (required for signature based approvals)
tokenName:
type: string
description: Token name for EIP-712 domain (required for signature based approvals)
example: USD Coin
tokenVersion:
type: string
description: Token version for EIP-712 domain (required for signature based approvals)
example: '2'
DepositStatusResponse:
type: object
required:
- status
properties:
status:
type: string
enum:
- PROCESSING
- BRIDGING
- SUCCESS
- FAILED
- EMERGENCY_WITHDRAW
description: 'Current status of the deposit.
- `PROCESSING`: Deposit is queued or being handled on the source chain.
- `BRIDGING` (cross-chain only): Source-side funds movement succeeded and is bridging to the destination chain. Same-chain deposits go straight to final `SUCCESS` or `FAILED` status.
- `SUCCESS`: Deposit has been successfully completed and funds are in the protocol.
- `FAILED`: Deposit transaction has failed (e.g., insufficient gas, transaction reverted).
- `EMERGENCY_WITHDRAW`: Destination-side deposit could not complete; funds were recovered via emergency withdrawal.
'
protocol:
type:
- string
- 'null'
enum:
- Aave
- Morpho
- Euler
description: Target protocol once known; may be null while still in `PROCESSING`.
example: Aave
pool:
type:
- string
- 'null'
description: Target pool address once known; may be null while still in `PROCESSING`.
example: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd'
chain:
type:
- string
- 'null'
description: Target chain once known; may be null while still in `PROCESSING`.
example: linea
DepositResponse:
type: object
required:
- trackingId
properties:
trackingId:
type: string
description: Unique identifier to track deposit status
example: 550e8400-e29b-41d4-a716-446655440000
responses:
InternalError:
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
examples:
Internal Error:
value:
code: INTERNAL_ERROR
internalCode: INTERNAL_ERROR
message: An unexpected error occurred while processing your request
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
RateLimitExceeded:
description: 'Too many requests for this endpoint. Limits are enforced per client IP for the public API routes backed by `RebalancerResource` (and related resources using the same filter).
Response headers (when throttled):
- `Retry-After`: seconds to wait before retrying (matches the rate-limit window duration for that endpoint).
- `X-RateLimit-Limit`: maximum requests allowed in the window (e.g. `1`).
- `X-RateLimit-Remaining`: remaining requests in the window (`0` when throttled).
- `X-RateLimit-Reset`: Unix timestamp (seconds) when the limit window resets.
`internalCode` in the JSON body is `THROTTLE_PER_IP` for IP-scoped limits (other values may apply for different scopes in the backend).
'
headers:
Retry-After:
description: Seconds to wait before retrying this endpoint.
schema:
type: integer
example: 3
X-RateLimit-Limit:
description: Maximum number of requests allowed in the current window for this endpoint.
schema:
type: integer
example: 1
X-RateLimit-Remaining:
description: Remaining requests in the current window.
schema:
type: integer
example: 0
X-RateLimit-Reset:
description: Unix timestamp (seconds) when the current limit window resets.
schema:
type: integer
format: int64
example: 1713264123
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
examples:
rateLimitExceededPerIp:
summary: Rate limit exceeded (per client IP)
value:
code: RATE_LIMIT_EXCEEDED
internalCode: THROTTLE_PER_IP
message: Rate limit exceeded. Maximum 1 requests per 3 seconds allowed. Please try again later.
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: 3
UnauthorizedNoHeader:
description: No authorization header provided
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
examples:
unauthorizedNoHeader:
$ref: '#/components/examples/UnauthorizedNoHeader'
Forbidden:
description: User is not authorized to perform this action
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
examples:
forbiddenGeneric:
summary: Forbidden - not authorized
value:
code: FORBIDDEN
internalCode: FORBIDDEN_GENERIC
message: User is not authorized to perform this action
requestId: 2c2f3dc1-d19a-49cb-b695-37d025e551b3
retryAfterSeconds: null
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: API key required for all endpoints.
JwtAuth:
type: apiKey
in: header
name: Authorization
description: 'JWT issued by POST /v1/auth/verify. Pass as Authorization: Bearer <token>.
x-agent-hint: agentcash and other agentic wallets strip the Authorization header for their own SIWX flow. Use X-MetaLend-JWT: Bearer <token> instead — the backend accepts both headers. Affected endpoints: POST /v1/deposits, POST /v1/withdrawals, PUT /v1/config.
'
OriginHeader:
type: apiKey
in: header
name: Origin
description: 'Required for CORS requests from browsers. Must match the allowed origins configured for the API key. Example: Origin: https://app.metalend.tech. Localhost is always allowed but must be specified.
'
externalDocs:
description: Litepaper
url: https://metalend-inc.gitbook.io/litepaper
x-provenance:
method: harvested
publisher: MetaLend
source: https://api.metalend.tech/openapi.json
note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json);
stamped by stamp-openapi-provenance.py (roadmap#793)