POST/v1/partner/end_users/{external_id}/deposit

Deposit

Deposits funds from the end user's wallet into the specified portfolio. The API automatically swaps from USDC to the portfolio's underlying token via 1inch if the token differs. This is a synchronous HTTP call — the connection is held open for 5–30 seconds while the on-chain transaction confirms. Supports both Entra token + user token.

Returns a post-deposit snapshot of the portfolio. To retrieve the on-chain transaction hash or swap details, use GET .../transactions after the deposit completes.

Idempotency-Key is required. See Idempotency.

Path parameters

external_idstringrequired

Your stable identifier for the end user.

Headers

Authorizationstringrequired

Entra M2M access token. Format: Bearer <token>. See Entra authentication.

X-User-Tokenstringoptional

Partner-minted JWT for the end user. Required in user-scoped. The sub claim must equal external_id. See User authentication.

Idempotency-Keystringrequired

UUID v4 uniquely identifying this logical deposit operation. If the connection drops and you retry, send the same key — you will receive the same response without re-executing the deposit. See Idempotency.

Content-Typestringrequired

Must be application/json.

Body

portfolio_idstringrequired

UUID of the portfolio to deposit into. Returned by POST .../portfolios as portfolio_id.

amount_minorstringrequired

Amount to deposit in the portfolio's token minor units (wei string). For USDC (6 decimals), "10000000" = 10 USDC. Must be a numeric string — no decimals.

Example request

import { randomUUID } from 'node:crypto';
 
const baseUrl = process.env.YIELDFORCE_API_BASE_URL ?? 'https://yieldforce.io/api';
 
const res = await fetch(`${baseUrl}/v1/partner/end_users/alice-bunq-id/deposit`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${entraToken}`,
    'X-User-Token': partnerJwt,
    'Idempotency-Key': randomUUID(), // generate once per logical operation
  },
  body: JSON.stringify({
    portfolio_id: 'jar_01HZ4KXQM5E8WRTYN3P7VBJD6F',
    amount_minor: '10000000', // 10 USDC
  }),
  // Set HTTP client timeout to at least 60s — on-chain txs take 5-30s
});
const data = await res.json();

Response

201 Deposit confirmed — post-deposit portfolio snapshot

{
  "status": "confirmed",
  "portfolio": {
    "portfolio_id": "jar_01HZ4KXQM5E8WRTYN3P7VBJD6F",
    "name": "USDC vault on Base",
    "description": null,
    "protocol": "morpho",
    "chain_id": "84532",
    "token_address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
    "market_address": "0x6A0935DEF442D92c3456FBb38B888375F022C646",
    "token_symbol": "USDC",
    "token_decimals": 6,
    "deposited": "10000000",
    "yield_earned": "0",
    "yield_earned_realized": "0",
    "total_balance": "10000000",
    "compounding_enabled": true,
    "created_at": "2026-05-20T10:00:00.000Z",
    "updated_at": "2026-05-20T10:02:00.000Z"
  }
}

Connection drop recovery

If your HTTP connection drops before the response arrives, the on-chain transaction may still be completing. Do not retry with a new Idempotency-Key — that would submit a second deposit. Instead:

  1. Retry the same request with the same Idempotency-Key. If the server has the result cached, you will get the response immediately.
  2. If retry also times out, poll GET .../transactions for a recent deposit transaction on this portfolio_id to confirm whether it landed on-chain.

Configure your HTTP client timeout to at least 60 seconds for this endpoint.

Errors

400 validation_errorportfolio_id is missing or amount_minor is not a valid numeric string.

400 idempotency_key_required — The Idempotency-Key header is missing.

401 token_missing — No Authorization: Bearer header on the request.

401 invalid_entra_token — Token is expired, malformed, or has an unexpected audience.

401 invalid_user_token — The X-User-Token failed signature verification or is expired.

403 sub_url_mismatch — The sub claim in X-User-Token does not match external_id in the URL.

404 end_user_not_found — No user with this external_id exists, or the portfolio does not belong to this user.

409 idempotency_key_in_use_with_different_params — An Idempotency-Key was reused with a different request body. Generate a new key for a different logical operation.

422 insufficient_balance — The user's wallet does not have enough USDC to cover amount_minor.

504 on_chain_timeout — The on-chain transaction did not confirm within the allowed window. Poll GET .../transactions to check whether it eventually landed.