# Deposit into a Product

> Coming soon, upon request — this feature is turned on for your tenant by the Aurea team. [Contact us](https://www.aureahub.com/contact)

Deposits an amount of the product's asset from one of the user's wallets.

## Overview

- Your tenant must offer the product on the network and the product take deposits (`403` `EARN_PRODUCT_OFF`, `409` `EARN_PRODUCT_PAUSED`); your tenant's limits apply (`400` `EARN_AMOUNT_OUT_OF_LIMITS`) and the wallet must hold the amount (`400` `EARN_INSUFFICIENT_BALANCE`).
- The user must have accepted the product's current disclosure: `409` `EARN_DISCLOSURE_NOT_PUBLISHED` while none is published (`This product takes no deposit yet: its disclosure is not published.`), `409` `EARN_DISCLOSURE_NOT_ACCEPTED` with its `version` until the user accepts it ([Disclosure](https://docs.aureahub.com/docs/earn-disclosure.md)).
- The approval, when one is needed, is of exactly the amount. Before anything is built the product is read again ([Readings and Limits](https://docs.aureahub.com/docs/guide-earn.md)).
- A custodial wallet: Aurea signs and sends at once and answers the operation `completed`, `failed`, or `broadcast` when a receipt is late. A client-side or MPC wallet: the operation is answered `submitted` with `signing.steps` — see below.
- `201` with the operation. An optional `Idempotency-Key` makes a retry safe ([Retries](https://docs.aureahub.com/docs/guide-earn.md)).

## Endpoint

### `POST /v1/earn/deposits`

Authentication: bearer token required.

Deposits an amount of the product's asset from one of the user's wallets.

**Headers**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Idempotency-Key` | string | no | Optional. Up to 255 letters, digits, - or _; see [Retries](https://docs.aureahub.com/docs/guide-earn.md) |

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `productId` | string | yes | The product's identifier |
| `amount` | string | yes | In the asset's smallest unit, as a string of digits |
| `isTestnet` | boolean | yes | `true` testnet, `false` mainnet |
| `walletId` | string | no | One of the user's EVM wallets on the network; without it, the first one somebody can sign for |
| `route` | string | no | `direct`, `bridge` or `secondary_market` ([Routes and Chains](https://docs.aureahub.com/docs/guide-earn.md)) |
| `chainId` | integer | no | The chain to operate on; without it, the one the wallet is on |

**Responses**

`201` Awaiting Signatures

```json
{
  "operationId": "3f9a…",
  "productId": "lumen",
  "kind": "deposit",
  "route": "direct",
  "signer": "client",
  "state": "submitted",
  "isTestnet": false,
  "walletId": "7c1e…",
  "walletAddress": "0x2f4B…",
  "chain": "gnosis",
  "chainId": 100,
  "assetAddress": "0xcB44…C56E",
  "amount": "50000000000000000000",
  "withdrawAll": false,
  "quote": {
    "apy": 2.41,
    "apyBasisPoints": 241,
    "rateSource": "onchain",
    "observedAt": "2026-10-05T10:00:05.000Z",
    "expectedAmount": "50000000000000000000",
    "fee": "0",
    "assetDecimals": 18
  },
  "txHashes": [],
  "failureCode": null,
  "signing": {
    "walletAddress": "0x2f4B…",
    "expiresAt": "2026-10-05T10:16:00.000Z",
    "steps": [
      {
        "stepIndex": 0,
        "purpose": "approve",
        "amount": "50000000000000000000",
        "counterparty": "0x…",
        "txHashToSign": "0x…",
        "to": "0xcB44…C56E",
        "data": "0x095ea7b3…",
        "value": "0",
        "chainId": 100,
        "nonce": 12,
        "gasLimit": "60000",
        "maxFeePerGas": "3000000000",
        "maxPriorityFeePerGas": "1000000000"
      },
      {
        "stepIndex": 1,
        "purpose": "deposit",
        "amount": "50000000000000000000",
        "counterparty": "0x…",
        "txHashToSign": "0x…",
        "to": "0x…",
        "data": "0x…",
        "value": "0",
        "chainId": 100,
        "nonce": 13,
        "gasLimit": "300000",
        "maxFeePerGas": "3000000000",
        "maxPriorityFeePerGas": "1000000000"
      }
    ]
  },
  "createdAt": "2026-10-05T10:01:00.000Z",
  "updatedAt": "2026-10-05T10:01:00.000Z",
  "broadcastAt": null,
  "completedAt": null,
  "failedAt": null
}
```

`409` Disclosure Not Accepted

```json
{
  "statusCode": 409,
  "error": "ConflictError",
  "message": "Accept the product's disclosure before depositing: GET /v1/earn/products/{productId}/disclosure, then POST its acceptance.",
  "details": { "code": "EARN_DISCLOSURE_NOT_ACCEPTED", "productId": "lumen", "version": 1 }
}
```

## Signing the Steps

For a `signer: "client"` operation, sign each step's `txHashToSign` — the hash itself, with no message prefix — with the wallet, and send the signatures in the order of the steps to [Send Signatures](https://docs.aureahub.com/docs/earn-broadcast.md) before `signing.expiresAt`. An MPC wallet signs each hash with the signing ceremony ([Start Signing Ceremony](https://docs.aureahub.com/docs/mpc-sign-start.md)).

```javascript
import { SigningKey } from 'ethers';

// operation = answer of POST /v1/earn/deposits with signer 'client'
function signSteps(operation, privateKey) {
  const key = new SigningKey(privateKey);
  return operation.signing.steps.map((step) => {
    const sig = key.sign(step.txHashToSign);
    return { v: sig.yParity === 1 ? '0x1' : '0x0', r: sig.r, s: sig.s };
  });
}
```

---

Web version: https://docs.aureahub.com/#earn-deposit
