> ## Documentation Index
> Fetch the complete documentation index at: https://developer.moneyone.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Request Data

> Trigger a data pull for an already-approved consent.

Data Request triggers a data pull for an already-approved consent. Whether you need
to call this explicitly depends on the product's `fiFetch` configuration
(see [User Redirection](./user-redirection)): **`MANUAL`** products require this
call for each consent you want data for; **`AUTOMATIC`** products fetch data on
approval without it.

## Endpoint

```
POST /finpro/transaction/data-request
```

Base URL: provided to you at onboarding.

## Headers

| Header          | Description                             |
| --------------- | --------------------------------------- |
| `Content-Type`  | `application/json`                      |
| `Authorization` | `Basic base64(client_id:client_secret)` |

## Request body

```jsonc theme={null}
{
  "transactionId": "string",   // required
  "consentId": "string",       // required
  "requestId": "string"        // required — idempotency key only, see "Idempotency," below
}
```

<ParamField body="transactionId" type="string" required>
  The `transactionId` returned by Consent Creation.
</ParamField>

<ParamField body="consentId" type="string" required>
  The consent to trigger a data pull for.
</ParamField>

<ParamField body="requestId" type="string" required>
  Idempotency key — see "Idempotency," below.
</ParamField>

<Note>
  This call does not take a `fiuId` field — MoneyOne always resolves which FIU a
  consent belongs to from `consentId` itself. Use
  [Track Status](./track-status) if you need to know which FIU a given `consentId`
  belongs to.
</Note>

## Sample request

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://<base_url>/finpro/transaction/data-request' \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Basic <base64(client_id:client_secret)>' \
    --data '{
      "transactionId": "<transaction_id>",
      "consentId": "<consent_id>",
      "requestId": "<your_unique_request_id>"
    }'
  ```
</CodeGroup>

## Response

```jsonc theme={null}
{
  "status": "SUCCESS",
  "errorCode": null,
  "message": "string",
  "consentId": "string",
  "sessionId": "string"   // this fetch attempt's id — track progress via Status Lookup
}
```

## Idempotency — pay attention here

Each already-approved consent has a limited, metered number of data-pull calls,
following from the fetch frequency/duration declared for that consent when it was
raised with the Account Aggregator — this is not a billing concept. **Every call to
this endpoint — duplicate or not — consumes one, and a consumed slot cannot be
recovered.** Always use a fresh, unique `requestId` per intended call, and don't
retry blindly on a timeout without checking [Track Status](./track-status) first to
confirm whether the original call actually went through.

## Error Codes

**Duplicate `requestId`:**

```jsonc theme={null}
{
  "status": "FAILURE",
  "errorCode": "DUPLICATE_REFERENCE_ID",
  "message": "requestId was already used within the last 5 minutes"
}
```

**Identifier doesn't resolve:**

```jsonc theme={null}
{
  "status": "FAILURE",
  "errorCode": "TRANSACTION_NOT_FOUND",
  "message": "string"
}
```

`transactionId` doesn't resolve to any known transaction — checked before `consentId`
resolution.

```jsonc theme={null}
{
  "status": "FAILURE",
  "errorCode": "CONSENT_NOT_FOUND",
  "message": "string"
}
```

`consentId` doesn't resolve, or resolves under a different `transactionId` than
supplied.

```jsonc theme={null}
{
  "status": "FAILURE",
  "errorCode": "INVALID_CONSENT",
  "message": "Consent has expired" // or "Consent is not active", or "Consent is not configured for manual data requests"
}
```

The consent was found, but isn't currently usable for a data pull — either its status
isn't `ACTIVE` (including expired), or it isn't configured to allow manual/on-demand
data requests. The `message` field carries the specific reason; the `errorCode` is the
same for all three cases.

| Error Code               | HTTP status | Meaning                                                                                                                  |
| ------------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------ |
| `UNAUTHORIZED`           | 401         | `Authorization` header is missing, malformed, or the credentials don't match your onboarded `client_id`/`client_secret`. |
| `INVALID_REQUEST`        | 400         | Request body fails schema validation.                                                                                    |
| `DUPLICATE_REFERENCE_ID` | 400         | `requestId` collides with one used within the dedup window (5 minutes, by default).                                      |
| `TRANSACTION_NOT_FOUND`  | 404         | `transactionId` doesn't resolve to any known transaction.                                                                |
| `CONSENT_NOT_FOUND`      | 404         | `consentId` doesn't resolve, or resolves under a different `transactionId` than supplied.                                |
| `INVALID_CONSENT`        | 400         | The consent isn't currently usable for a data pull.                                                                      |

## Data-fetch webhook

Register your own webhook URL with MoneyOne at onboarding to be notified when a data
pull started by this call finishes. Delivery is **per-FIU, independently** — not
consolidated the way the consent callback is, since each Data Request call is already
scoped to one consent.

| Event             | `eventType` | Fires when                                                                                                                            |
| ----------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `DATA_READY`      | `DATA`      | Financial data was successfully fetched and is available for retrieval.                                                               |
| `DATA_DENIED`     | `DATA`      | The FIP refused the data-fetch request.                                                                                               |
| `SESSION_FAILED`  | `DATA`      | The data-fetch session failed, typically from an FIP timeout — often transient; retry with a new Data Request call before escalating. |
| `SESSION_EXPIRED` | `DATA`      | The session's time-to-live was exceeded before the FIP responded — retry with a new Data Request call if the consent is still active. |

### Payload shape

```jsonc theme={null}
{
  "timestamp": "string",
  "consentHandle": "string",
  "consentId": "string",
  "transactionId": "string",    // correlates this event with the parent journey
  "fiuId": "string",            // which of your onboarded FIUs this event is about
  "eventType": "DATA",
  "eventStatus": "string",      // DATA_READY / DATA_DENIED / SESSION_FAILED / SESSION_EXPIRED
  "eventMessage": "string",
  "productID": "string",
  "fetchType": "string",
  "consentExpiry": "string",
  "dataExpiry": "string",
  "firstTimeFetch": true,       // true only if this is the first-ever successful fetch for this consent; false on every subsequent fetch
  "sessionId": "string",        // present on SESSION_FAILED
  "sessionStatus": "string",    // DATA_READY / PARTIAL_DATA_READY / DATA_DENIED / SESSION_FAILED / SESSION_EXPIRED
  "dataFetchDate": "string",    // when the fetch completed
  "linkRefNumbers": [
    {
      "linkRefNumber": "string",
      "fiStatus": "READY | DENIED | TIMEOUT",
      "fipName": "string",
      "fipId": "string",
      "maskedAccountNumber": "string"
    }
  ]
}
```

<Note>
  `linkRefNumbers[]` is **per-account** — a single data-fetch session can have some
  accounts ready and others denied or timed out in the same event. Check each
  account's `fiStatus` individually rather than treating the event as all-or-nothing.
</Note>

<Note>
  If your webhook is unreachable, or you'd rather poll: [Track Status](./track-status)
  remains available at any time — pass `transactionId` alone for every consent under a
  journey in one call, or specific `consentId`/`sessionId`/`consentHandle` values for
  detailed, per-session, per-account status. Use webhook as the primary signal and
  polling as a complement, not a pure fallback used only when webhooks fail.
</Note>

## Next step

Retrieve the data once ready via [Fetch Data](./fetch-data), tracking progress in the
meantime via [Track Status](./track-status).
