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

# Testing & sandbox

> Integration test environments, and safe data for Partner API development.

<Warning>
  Sandbox tokens, card numbers, and API keys in this documentation are **examples only**. Values may differ per environment or tenant. Never use production credentials in shared sandboxes or commit secrets to source control.
</Warning>

## Environments and base URLs

| Environment                            | Base URL (REST)                         | Notes                                                                       |
| -------------------------------------- | --------------------------------------- | --------------------------------------------------------------------------- |
| CV / integration (default in this doc) | `https://raas-partner-cv.nomas.cash/v1` | Example non-production host; your contract may use a different hostname.    |
| mTLS (same logical API)                | `https://mtls-partner-cv.nomas.cash/v1` | See [Introduction](/raas/api-reference/introduction) for certificate usage. |

## Authentication in tests

* Send header **`api_key`** on every request (value issued for your tenant in that environment).
* Scopes in the Partner API are grouped in the OpenAPI tags **`Partner`**, **`Partner Send`**, and **`Partner Full`**. Use an API key that includes the scope required by the endpoint you are calling.

<Tip>
  Keep `api_key` on your **server** only. Do not embed it in mobile apps or public web clients.
</Tip>

## Test card number (sandbox)

Use these **sandbox-only** PANs where your flow accepts a test card number (for example via VGS or a widget that tokenizes before RaaS). Confirm with Leapfinancial which rows apply to your tenant and processor; lists can change.

| Network    | Card number           | CVV   |
| ---------- | --------------------- | ----- |
| Visa       | `4111 1111 1111 1111` | —     |
| Visa       | `4622 9431 2701 3705` | `838` |
| Visa       | `4622 9431 2701 3713` | `043` |
| Visa       | `4622 9431 2701 3721` | `258` |
| Visa       | `4622 9431 2701 3739` | `942` |
| Visa       | `4622 9431 2701 3747` | `370` |
| Mastercard | `2222 4200 0000 1113` | —     |
| Mastercard | `2222 6300 0000 1125` | —     |
| Mastercard | `5555 5555 5555 4444` | —     |

## Card field tokenization (VGS)

Some integrations send **sensitive card fields** (PAN, CVV) to **Very Good Security (VGS)** outbound proxy endpoints instead of posting raw values to RaaS. The **vault identifier** in the hostname is **tenant- or environment-specific**; replace it with your own value (for example a REST Client variable `{{vgsVaultId}}` declared in your `.http` file).

**Sandbox URL pattern**

```text theme={null}
https://{{vgsVaultId}}.sandbox.verygoodproxy.com/post
```

**Example request** (`Content-Type: application/json`):

```http theme={null}
POST https://{{vgsVaultId}}.sandbox.verygoodproxy.com/post
Content-Type: application/json

{
    "CardNumber": "4111111111111111",
    "Cvv": "123"
}
```

**Example response** (shape may vary slightly by VGS route configuration; tokens below are illustrative):

```json theme={null}
{
  "data": "{\"CardNumber\": \"41111111\"}",
  "json": {
    "CardNumber": "tok_sandbox_9PNgfqqpdpyQpnD1jYkdw1_1111",
    "Cvv": "tok_sandbox_cE5jCyTLtr2cC666to2ie2"
  }
}
```

Use the values under **`json`** (e.g. `tok_sandbox_…`) as **`number`** / **`securityCode`** (or equivalent fields) when calling Partner funding or card endpoints—**never** send live PAN/CVV to RaaS from untrusted clients.

<Warning>
  Do not commit real card data, production vault IDs, or proxy credentials. The PAN/CVV in the request example are **test-only** patterns for sandbox documentation.
</Warning>

## UBN and bank-style test data

For `POST /user/funding/source/ubn-account/add/{userToken}` (and related flows), sandbox account numbers are often **numeric strings** in a fixed length for your country (for example a value shaped like `002320275621938815`). **Validate** the exact test account list for your tenant and country with Leap—do not assume one global test account across all partners.

## Phones, users, and contacts

* Use **E.164** phone numbers with the correct `dial country code` for `getUserTokenV2` and registration flows.
* For **duplicate contact** tests, reuse the same `phone` under the same `userToken` and expect a **400**-class error with a clear `reason` / `code` (see OpenAPI for `createContact`).

## `getUserTokenV2` — scenario matrix

Use **`POST /auth/get-user-token-v2`** with a valid **`api_key`** so the request reaches this handler. Body: `GetUserTokenParams` (`phoneNumber` and/or `email`, optional `countryCode`). The table lists **handler** outcomes (`successResponse`, `badRequestResponse`, `notFoundResponse`, `errorResponse`) **and** the **401** case now declared in OpenAPI via `@Response<ErrorResponse>(401, "Missing or invalid API key")` (enforcement may still occur at the gateway before TSOA).

Ready-to-run examples for these rows live in **`clients/clientv5/partner-ask-v1.http`** — search for `getUserToken-v2 —`.

| HTTP    | Scenario                      | How to reproduce                                                                                                                                                     | Typical JSON (`reason` / `code`)                                                                                                        |
| ------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| **200** | Known user by phone or email  | E.164 `phoneNumber` (with `+`) or `email` that already exists for the tenant; align `countryCode` with the number when you send it.                                  | `{ "userId": "…", "status": "…" }` (optional fields depend on tenant / CIP).                                                            |
| **401** | Missing / bad API key         | Omit `api_key` or send an invalid/expired partner key.                                                                                                               | OpenAPI example: `Missing or invalid API key`; live stacks may return a gateway-specific body.                                          |
| **400** | Tenant could not be loaded    | First `tenantService.getById` returns no tenant for the resolved `request.tenant.id` (environment-specific).                                                         | `ERROR_INVALID_TENANT`                                                                                                                  |
| **400** | Missing alias                 | Empty JSON `{}` or omit both `phoneNumber` and `email`.                                                                                                              | `ERROR_INVALID_SCHEMA`                                                                                                                  |
| **400** | Invalid email shape           | String that fails the server-side email check, e.g. `"no-es-un-email"`, or an email containing a null byte.                                                          | `ERROR_INVALID_EMAIL_FORMAT`                                                                                                            |
| **400** | Phone not E.164               | `phoneNumber` without a leading `+` (e.g. national digits only).                                                                                                     | `INVALID_PHONE_NUMBER`                                                                                                                  |
| **400** | Country mismatch              | Valid E.164 for one country with `countryCode` that does not match **platform phone validation** (e.g. MX mobile with `countryCode` forced to `US`).                 | `ERROR_COUNTRY_NOT_SUPPORTED`                                                                                                           |
| **404** | User not found                | `email` or `phoneNumber` that is syntactically valid but **not registered** in that environment / tenant.                                                            | `ERROR_USER_NOT_FOUND`                                                                                                                  |
| **500** | Internal / downstream failure | Not reliably simulated from a static HTTP file; may appear on datastore, CIP, tenant, TPE, or any unexpected exception after **`NumiBadRequestError`** is ruled out. | Handler returns the **generic** internal error (`ERROR_INTERNAL_SERVER_ERROR`); retry with backoff and support correlation if provided. |

<Tip>
  For **`ERROR_COUNTRY_NOT_SUPPORTED`**, use a **real sandbox mobile** your TPE accepts, then deliberately pass the wrong `countryCode`. If validation is stubbed in a local dev stack, this row may not fire until you hit a CV-like environment.
</Tip>

<Note>
  Responses often include both **`reason`** (human-readable) and **`code`** (machine-readable). Treat **400** as “fix the request or tenant context”; **404** as “user does not exist — register or fix the alias”; **500** as “retry later / escalate with timestamps.” For **`getUserTokenV2`**, **500** uses the **same generic** internal payload (`ERROR_INTERNAL_SERVER_ERROR`).
</Note>

<span id="register-user-v2-scenario-matrix" />

## `registerUserV2` — scenario matrix

`POST /auth/register-user-v2`. Handler returns **200** with `userId` when registration is queued; **400** for tenant, country, schema, DOB, already enrolled, or phone validation (`NumiBadRequestError`); **500** for unexpected or platform errors (generic body, no raw `error.message`). **401** is documented in OpenAPI (`@Response<ErrorResponse>(401, "Missing or invalid API key")`).

| HTTP    | Scenario                                           | How to reproduce (minimal)                                                         | Expected `code` / body                                                     |
| ------- | -------------------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| **200** | New user accepted                                  | Valid `RegisterUserParams`, phone/email not already registered.                    | `userId` + optional `status`                                               |
| **401** | Missing / bad API key                              | Omit `api_key` or invalid partner key.                                             | OpenAPI `401` description; body may be gateway-shaped.                     |
| **400** | Invalid tenant / country / schema / DOB / enrolled | Missing tenant, `countryCode` ≠ tenant, invalid fields, bad DOB, or existing user. | `ERROR_INVALID_*` / `ERROR_USER_ALREADY_ENROLLED` / phone validation codes |
| **500** | Platform / unexpected                              | Downstream failure after validation.                                               | `ERROR_INTERNAL_SERVER_ERROR`                                              |

<span id="get-profile-scenario-matrix" />

## `getProfile` — scenario matrix

`GET /user/profile/{phoneOrEmail}`. Resolves a registered user by **E.164 phone** (with `+`) or **email**, loads the subscriber record for `createdAt`, and enriches the response with **CIP process `status`** from `cipService.getProcessInfo`. Returns a **`UserProfile`** with identity, contact, address, optional geo coordinates (`latitude`, `longitude`), and CIP status. **404** when the user or subscriber is missing; **500** on unexpected storage/CIP/platform errors (sanitized `ErrorResponse`, no raw `error.message`). **401** is declared in OpenAPI (`@Response<ErrorResponse>(401, "Missing or invalid API key")`). OpenAPI per-status tables come from **`openapi-examples.json`** (`_mintlifyResponseDescriptions.getProfile`); keep this section and that JSON **in sync**.

Ready-to-run examples live in **`clients/clientv5/partner-ask-v1.http`** — search for `getProfile —`.

| HTTP    | Scenario              | How to reproduce (minimal)                                                                                    | Expected `code` / body                                                                                       |
| ------- | --------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| **200** | Profile OK            | Path `phoneOrEmail` is a registered phone or email for the tenant; user has a subscriber record and CIP data. | `UserProfile` (`id`, names, contact, address, CIP `status`, `createdAt`, optional `latitude` / `longitude`). |
| **401** | Missing / bad API key | Omit `api_key` or send an invalid/expired partner key.                                                        | OpenAPI `401`; body may be gateway-shaped.                                                                   |
| **404** | User not found        | Phone or email not registered in the tenant.                                                                  | `ERROR_USER_NOT_FOUND`                                                                                       |
| **404** | Subscriber not found  | User exists in user store but has no subscriber mapping.                                                      | `ERROR_SUBSCRIBER_NOT_FOUND`                                                                                 |
| **422** | Path validation       | TSOA path parameter validation failure (rare in normal use).                                                  | `ValidateError`                                                                                              |
| **500** | CIP not found         | User/subscriber exist but CIP record is missing when `getProcessInfo` runs.                                   | `ERROR_CIP_NOT_FOUND`                                                                                        |
| **500** | Internal / downstream | User or subscriber store throws, or other unexpected `NumiError` after client-error paths ruled out.          | `ERROR_INTERNAL_SERVER_ERROR` or mapped `NumiError` `code`                                                   |

<span id="list-contacts-scenario-matrix" />

## `listContacts` — scenario matrix

`GET /user/contacts/{userToken}`. Resolves the path `userToken` via user storage: **404** if there is no user; **200** with an array (possibly empty) when the user exists; **500** if contact storage throws. Use **`api_key`** with `partner` or `partner_send` scope (**401**/**403** come from the gateway when the key is missing, invalid, or out of scope).

| HTTP    | Scenario         | How to reproduce (minimal)                                        | Expected `code` / body           |
| ------- | ---------------- | ----------------------------------------------------------------- | -------------------------------- |
| **200** | List OK          | Valid `userToken` for an existing user.                           | Array of contacts (may be empty) |
| **404** | Unknown user     | Random path segment or deleted user id (not found in user store). | `ERROR_USER_NOT_FOUND`           |
| **401** | No / bad API key | Omit `api_key` or use a wrong key.                                | Environment-specific             |
| **403** | Scope            | Key without `partner` / `partner_send`.                           | Environment-specific             |
| **500** | Storage error    | Rare failure from contact store.                                  | `ERROR_INTERNAL_SERVER_ERROR`    |

<span id="create-contact-scenario-matrix" />

## `createContact` — scenario matrix

`POST /user/contacts/{userToken}`. **404** when `userToken` does not resolve to a user; **400** for missing names, bad phone, missing country, duplicates; **500** sanitized on unknown errors (`NumiBadRequestError` / `NumiError` mapped in catch). **401** is documented in OpenAPI (same `@Response<ErrorResponse>(401, …)` pattern as `listContacts`). **422** TSOA `ValidateError` is no longer declared on this route; structural validation errors surface as **400** / **500** per handler.

| HTTP    | Scenario              | How to reproduce (minimal)                                         | Expected `code` / body                          |
| ------- | --------------------- | ------------------------------------------------------------------ | ----------------------------------------------- |
| **200** | Contact stored        | Valid body + normalized phone.                                     | `{ "reason": "Contact created", "code": "OK" }` |
| **404** | Unknown path user     | `userToken` not in user store.                                     | `ERROR_USER_NOT_FOUND`                          |
| **401** | Missing / bad API key | Omit `api_key` or wrong key / scope.                               | OpenAPI `401`; body may be gateway-specific.    |
| **400** | Validation / business | Missing `firstName`/`lastName`, bad `phone`, duplicate phone, etc. | `ERROR_*` from `ErrorCodes`                     |
| **500** | Unexpected            | Rare storage failures after validation.                            | `ERROR_INTERNAL_SERVER_ERROR`                   |

<span id="update-contact-scenario-matrix" />

## `updateContact` — scenario matrix

`PUT /user/contacts/{userToken}`. **404** when `userToken` does not resolve to a user; **400** / **500** for payload or storage errors (sanitized). **401** documented in OpenAPI like other contact routes.

| HTTP    | Scenario              | How to reproduce (minimal)                           | Expected `code` / body                          |
| ------- | --------------------- | ---------------------------------------------------- | ----------------------------------------------- |
| **200** | Updated               | Valid token + existing contact + valid body.         | `{ "reason": "Contact updated", "code": "OK" }` |
| **404** | Unknown path user     | `userToken` not in user store.                       | `ERROR_USER_NOT_FOUND`                          |
| **401** | Missing / bad API key | Omit `api_key` or wrong key / scope.                 | OpenAPI `401`.                                  |
| **400** | Invalid payload       | Body fails validation rules returned by the handler. | `ERROR_*`                                       |
| **500** | Unexpected            | Contact missing or storage error.                    | `ERROR_INTERNAL_SERVER_ERROR`                   |

<span id="get-available-payment-methods-scenario-matrix" />

## `getAvailablePaymentMethods` — scenario matrix

`GET /user/corridors/available-receiver-methodtypes/{userToken}` (`getAvailableReceiverMethodTypes` in code). Returns method type strings for corridors.

| HTTP    | Scenario              | How to reproduce (minimal)                                                     | Expected `code` / body                        |
| ------- | --------------------- | ------------------------------------------------------------------------------ | --------------------------------------------- |
| **200** | Types resolved        | Valid user and tenant; corridors configured.                                   | `["DebitCard", ...]`                          |
| **404** | Unknown path user     | `userToken` not found in user store.                                           | `ERROR_USER_NOT_FOUND`                        |
| **401** | Missing / bad API key | Omit `api_key` or invalid key for `partner` / `partner_send` / `partner_full`. | OpenAPI `401` via `@Response<ErrorResponse>`. |
| **500** | Resolution failure    | Tenant/corridor errors or unexpected exception after user resolved.            | Generic internal `reason`                     |

<span id="get-receiving-methods-scenario-matrix" />

## `getReceivingMethods` — scenario matrix

`GET /user/funding/source/get-receiving-methods/{userToken}`. **400** invalid tenant; **200** SOF list; **500** downstream / `NumiError`.

| HTTP    | Scenario              | How to reproduce (minimal)                              | Expected `code` / body                               |
| ------- | --------------------- | ------------------------------------------------------- | ---------------------------------------------------- |
| **200** | SOF list              | Valid tenant + user + query countries.                  | `SourceOfFunding[]`                                  |
| **401** | Missing / bad API key | Omit `api_key` or invalid `partner` key.                | OpenAPI `401` via `@Response<ErrorResponse>`.        |
| **400** | Invalid tenant        | Request without resolvable tenant / missing tenant row. | `ERROR_INVALID_TENANT`                               |
| **500** | Service error         | Funding service / unexpected errors.                    | `ERROR_INTERNAL_SERVER_ERROR` or `NumiError` payload |

<span id="create-funding-card-scenario-matrix" />

## `createFundingCard` (add card) — scenario matrix

`POST /user/funding/source/card/add/{userToken}` (`OperationId`: `createFundingCard`). **400** card/issuer validation; **200** existing or new PM; **500** unexpected.

| HTTP    | Scenario                         | How to reproduce (minimal)                                      | Expected `code` / body                        |
| ------- | -------------------------------- | --------------------------------------------------------------- | --------------------------------------------- |
| **200** | Card added or duplicate returned | Valid sandbox token + valid card payload (or duplicate number). | `RaaSPaymentMethod`                           |
| **401** | Missing / bad API key            | Omit `api_key` or key without `partner_send` / `partner`.       | OpenAPI `401` via `@Response<ErrorResponse>`. |
| **400** | Declined / invalid               | Bad expiry, BIN, processor decline, user not found.             | Parsed card error object                      |
| **500** | Unexpected                       | Non-`NumiBadRequestError` failures.                             | `ERROR_INTERNAL_SERVER_ERROR`                 |

<span id="add-ubn-account-scenario-matrix" />

## `addUBNAccount` — scenario matrix

`POST /user/funding/source/ubn-account/add/{userToken}`. **403** user/tenant; **400** UBN validation / duplicate; **500** platform failure.

| HTTP    | Scenario                | How to reproduce (minimal)                               | Expected `code` / body                                       |
| ------- | ----------------------- | -------------------------------------------------------- | ------------------------------------------------------------ |
| **200** | UBN added               | Valid user, subscriber, sandbox UBN.                     | `AddPaymentMethodResponse`                                   |
| **401** | Missing / bad API key   | Omit `api_key` or invalid multi-scope key.               | OpenAPI `401` via `@Response<ErrorResponse>`.                |
| **400** | Invalid UBN / duplicate | Bad account algorithm or `PAYMENTMETHOD_ALREADY_EXISTS`. | `UBN_VALIDATION_ERROR` / `UBN_ALREADY_ADDED`                 |
| **403** | User/tenant             | Unknown `userToken` or tenant mismatch paths.            | `USER_NOT_FOUND` / `INVALID_TENANT` (as returned by handler) |
| **500** | Platform                | `NumiError` / unknown errors.                            | `ERROR_INTERNAL_SERVER_ERROR` or mapped `NumiError`          |

<span id="get-payment-method-v2-scenario-matrix" />

## `getPaymentMethodV2` — scenario matrix

`GET /user/funding/source/get-payment-method-v2/{userToken}?id=...`. **200** when the payment method exists for the subscriber; **404** when there is no subscriber or the `id` is not in the user’s methods; **400** for other `NumiBadRequestError` paths from downstream; **500** for `NumiError` or unexpected failures.

| HTTP    | Scenario              | How to reproduce (minimal)                                              | Expected `code` / body                              |
| ------- | --------------------- | ----------------------------------------------------------------------- | --------------------------------------------------- |
| **200** | PM found              | Valid `userToken`, subscriber, existing `id`.                           | `RaaSPartnerPaymentMethod`                          |
| **401** | Missing / bad API key | Omit `api_key` or invalid key.                                          | OpenAPI `401` via `@Response<ErrorResponse>`.       |
| **400** | Bad request           | Other `NumiBadRequestError` from funding/connectors (not PM-not-found). | `reason` + `code`                                   |
| **404** | Unknown path user     | `userToken` not in user store.                                          | `ERROR_USER_NOT_FOUND`                              |
| **404** | Subscriber missing    | User path resolves but has no subscriber row.                           | `ERROR_SUBSCRIBER_NOT_FOUND`                        |
| **404** | PM not in wallet      | Valid user + random/non-owned `id` (e.g. new UUID).                     | `ERROR_PAYMENT_METHOD_NOT_FOUND`                    |
| **500** | Internal              | `NumiError` or unexpected exception.                                    | `ERROR_INTERNAL_SERVER_ERROR` or mapped `NumiError` |

<span id="request-money-v2-scenario-matrix" />

## `requestMoneyV2` — scenario matrix

`POST /user/operations/request-money-v2/{userToken}`. **404** when path `userToken` does not resolve; **400** for corridor / contact / PM validation; **500** uses mapped `NumiError` or generic internal (no raw exception text). **401** in OpenAPI for missing/invalid API key.

| HTTP    | Scenario              | How to reproduce (minimal)                                | Expected `code` / body                       |
| ------- | --------------------- | --------------------------------------------------------- | -------------------------------------------- |
| **200** | Request created       | Valid payload + corridor + destination PM.                | `OperationResponsePartner`                   |
| **401** | Missing / bad API key | Omit `api_key` or key without `partner` / `partner_full`. | OpenAPI `401`.                               |
| **404** | Unknown path user     | `userToken` not in user store.                            | `ERROR_USER_NOT_FOUND`                       |
| **400** | Validation            | Unsupported destination, PM, or corridor rules.           | `ERROR_*` / handler `reason`+`code`          |
| **500** | Unexpected            | `NumiError` or unknown after bad-request handling.        | `ERROR_INTERNAL_SERVER_ERROR` or `errorCode` |

<span id="operation-quote-v2-scenario-matrix" />

## `operationQuoteV2` — scenario matrix

`POST /user/operations/operation-quote-v2/{userToken}`. **400** invalid quotation fields; **500** tenant/user/rate failures; **401** documented in OpenAPI.

| HTTP    | Scenario              | How to reproduce (minimal)                                     | Expected `code` / body                  |
| ------- | --------------------- | -------------------------------------------------------------- | --------------------------------------- |
| **200** | Quote OK              | Valid recipient id, amounts, PM ids.                           | `RaasQuoteTransactionResponse`          |
| **401** | Missing / bad API key | Omit `api_key` or invalid `partner_send` / `partner_full` key. | OpenAPI `401`.                          |
| **400** | Invalid payload       | Empty recipient, zero amount, empty currency.                  | `ERROR_INVALID_QUOTATION_REQUEST_DATA`  |
| **500** | Internal              | Downstream / unexpected.                                       | `INTERNAL_SERVER_ERROR` or mapped codes |

<span id="get-operation-status-scenario-matrix" />

## `getOperationStatus` — scenario matrix

`GET /user/operations/status/{userToken}/{operationId}`. **404** unknown user; **400** `NumiBadRequestError`; **500** otherwise; **401** in OpenAPI.

| HTTP    | Scenario              | How to reproduce (minimal)                            | Expected `code` / body |
| ------- | --------------------- | ----------------------------------------------------- | ---------------------- |
| **200** | Status                | Resolved user + valid operation id.                   | Status string          |
| **401** | Missing / bad API key | Omit `api_key` or invalid `partner` / `partner_send`. | OpenAPI `401`.         |
| **404** | Unknown path user     | `userToken` not resolved.                             | `ERROR_USER_NOT_FOUND` |
| **400** | Bad request           | Operation service `NumiBadRequestError`.              | `ErrorResponse`        |
| **500** | Internal              | Unexpected / `NumiError`.                             | Generic or `errorCode` |

<span id="get-operation-quote-scenario-matrix" />

## `getOperationQuote` — scenario matrix

`POST /user/operations/quotation/{userToken}`. Same auth pattern as other operations routes; **401** in OpenAPI.

| HTTP    | Scenario              | How to reproduce (minimal)                        | Expected `code` / body                         |
| ------- | --------------------- | ------------------------------------------------- | ---------------------------------------------- |
| **200** | Quote                 | Valid user + `QuoteTransactionBase`.              | `RaasQuoteTransactionResponse`                 |
| **401** | Missing / bad API key | Omit `api_key`.                                   | OpenAPI `401`.                                 |
| **404** | Unknown path user     | `userToken` not in user store.                    | `ERROR_USER_NOT_FOUND`                         |
| **400** | Bad input             | Quote validation failures.                        | Mapped `ErrorCodes`                            |
| **500** | Internal              | Missing tenant, invalid quotation data path, etc. | `ERROR_INTERNAL_SERVER_ERROR` or specific code |

<span id="pre-quote-scenario-matrix" />

## `preQuote` — scenario matrix

`POST /user/operations/pre-quote/{userToken}`. **500** on market/integration errors; **401** in OpenAPI.

| HTTP    | Scenario              | How to reproduce (minimal)               | Expected `code` / body                  |
| ------- | --------------------- | ---------------------------------------- | --------------------------------------- |
| **200** | Pre-quote             | Valid tenant + `PartnerPreQuoteRequest`. | `RaasPreQuoteResponse`                  |
| **401** | Missing / bad API key | Omit `api_key` or invalid key.           | OpenAPI `401`.                          |
| **500** | Internal              | `NumiError` or unexpected.               | `ERROR_INTERNAL_SERVER_ERROR` or mapped |

<span id="get-operation-scenario-matrix" />

## `getOperation` (operation detail) — scenario matrix

`GET /user/operations/detail/{id}`. **500** when operation missing or tenant mismatch (`OPERATION_NOT_FOUND`); **401** in OpenAPI.

| HTTP    | Scenario              | How to reproduce (minimal)                 | Expected `code` / body                  |
| ------- | --------------------- | ------------------------------------------ | --------------------------------------- |
| **200** | Detail                | Operation exists for partner tenant.       | `OperationDetailResponse`               |
| **401** | Missing / bad API key | Omit `api_key` or invalid multi-scope key. | OpenAPI `401`.                          |
| **500** | Not found / error     | Wrong id or tenant mismatch.               | `ERROR_OPERATION_NOT_FOUND` or internal |

<span id="get-operations-scenario-matrix" />

## `getOperations` — scenario matrix

`GET /user/operations/{userToken}`. **400** when user tenant ≠ request tenant; **401** in OpenAPI.

| HTTP    | Scenario              | How to reproduce (minimal)             | Expected `code` / body        |
| ------- | --------------------- | -------------------------------------- | ----------------------------- |
| **200** | History               | Valid user for tenant.                 | `OperationDetail[]`           |
| **401** | Missing / bad API key | Omit `api_key`.                        | OpenAPI `401`.                |
| **400** | Tenant mismatch       | `userToken` belongs to another tenant. | `ErrorResponse`               |
| **500** | Internal              | Datastore errors.                      | `ERROR_INTERNAL_SERVER_ERROR` |

<span id="get-frequent-contacts-scenario-matrix" />

## `getFrequentContacts` — scenario matrix

`GET /user/operations/frequent/{userToken}/{limit}`. Returns the top **`limit`** contacts derived from recent operations for **`userToken`**. OpenAPI merges per-status scenario tables from **`openapi-examples.json`** (`_mintlifyResponseDescriptions` → `getFrequentContacts`); keep this section and that JSON **in sync**.

| HTTP    | Scenario                          | How to reproduce (minimal)                                                                                  | Expected `code` / body                                                           |
| ------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| **200** | Frequent list                     | Valid `userToken` + positive numeric `limit` within supported bounds.                                       | `ContactInfo[]` (may be empty).                                                  |
| **401** | Missing / bad API key             | Omit `api_key` or use a key without `partner` / `partner_send` / `partner_full` as required by `@Security`. | OpenAPI `401` (`@Response<ErrorResponse>(401, "Missing or invalid API key")`).   |
| **400** | Bad input / `NumiBadRequestError` | Invalid `limit` (non-numeric, ≤ 0), or service rejects the request with `NumiBadRequestError`.              | `ErrorResponse` with mapped `reason` / `code`.                                   |
| **500** | Indexed query / internal          | Downstream failure from `getLastOperationsContact` or unexpected exception after validation.                | `ERROR_INTERNAL_SERVER_ERROR` (sanitized body; no raw stack or `error.message`). |

## Webhooks and async events

* Register a **reachable HTTPS** URL (or tunnel such as ngrok) for webhook callbacks in non-production.
* Verify **signature / shared secret** handling if your integration consumes outbound events.
* Use a unique **`correlationId`** on money operations so support can correlate logs across systems.

## Correlation IDs for money operations

* **`requestMoney`** requests **must** include a **`correlationId`**. That same value is **carried into the related funding operation**, so request money and its funding step share one correlation boundary for tracing and support.
* A **standalone or spontaneous send money** (not tied to that request-money → funding chain) **must** use its **own** **`correlationId`**.
* Treat **`correlationId`** as **unique per distinct money operation**. The **only** exception is the linked case above: funding reuses the **`correlationId`** you sent with **`requestMoney`**.

## Related pages

* [Introduction](/raas/api-reference/introduction) — mTLS, happy path, common HTTP errors.
