# JikoNet transfers

A JikoNet transfer — an **On-Us** transfer in the API — moves money between two accounts inside Jiko. Nothing touches an external network, so there is no cut-off, no return window and no clearing delay. The debit and the credit are two halves of one operation: a transfer either posts both legs or neither. There is no partial state.

Whether both ends belong to the same partner depends on the transfer type. Funding, defunding and internal reallocation address both pockets by ID and both are validated against your partnership, so both ends are always yours. Peer-to-peer addresses the recipient by their portal's account number, which resolves across the whole Jiko network — so a peer-to-peer transfer can reach a customer of a different partner.

div
## Prerequisites

### Feature flags

Feature flags are set by Jiko per partner and evaluated against the API user making the request. A call that needs a flag you do not have fails with `403`. Ask your Jiko point of contact for the ones you need.

| Flag | Needed for | Without it |
|  --- | --- | --- |
| `allowed_pocket_types` | Passing an explicit `type` when creating a pocket. A comma-separated list, for example `JIKO_PAY,JIKO_STORE`. A `type` outside the list is refused | `403` on pocket creation. Omitting `type` is accepted and you get your partnership's default type |


Nothing gates `POST /api/v1/transfers/on-us/` itself, and an On-Us counterparty — `type: "on_us"` with `name_match` verification — needs no flag either. The flag above matters only because the rail needs a particular kind of pocket, and that is what decides whether you can ask for one.

### Everything else

- **JikoPay pockets at both ends.** A portal on a JikoStore pocket does not carry the `ON_US` rail. Read the portal's `payment_rails` rather than assuming, and confirm with your Jiko point of contact which pocket types your partnership can open.
- **Approved customers and pockets in `OPEN` status** on both sides of the transfer.
- **A partner-owned facilitation account, for funding and defunding.** Jiko provisions it; you address it by pocket ID in `from_account` or `to_account`. Without one, `PARTNER_CUSTOMER_FUNDING` and `PARTNER_CUSTOMER_DEFUNDING` have no near end.
- **An `on_us` counterparty in `LINKED` status, for peer-to-peer.** Registered from the recipient portal's `account_number` and the account holder's exact `legal_name`. The recipient portal must be `OPEN`, must carry `ON_US`, and must not belong to the registering customer — a customer moving money between their own pockets uses `INTERNAL_REALLOCATION`, not a counterparty. A name mismatch stops the counterparty being created, and the error is about the name rather than the account.
- **Two pockets of the same customer, for internal reallocation.** `SECURITY_TRANSFER` is currently limited to JikoPay pockets.
- **Balance that can actually move.** Use `FULL_WITHDRAWAL` where you mean "everything", rather than reading a balance and sending it back as a requested amount.
- **A webhook subscription**, since the recommended `async_mode: true` reports progress only through events: `transfers.on-us.processing`, `transfers.on-us.success` and `transfers.on-us.rejected` on the originating side, `transfers.on-us.received` on the receiving side. Subscriptions are recorded against the API user that creates them.


## The four types

| `type` | Moves money | Typical use |
|  --- | --- | --- |
| `PARTNER_CUSTOMER_FUNDING` | From a partner-owned facilitation account to a customer's pocket | Disbursing funds to a customer |
| `PARTNER_CUSTOMER_DEFUNDING` | From a customer's pocket to a partner-owned facilitation account | Collecting funds from a customer |
| `PEER_TO_PEER` | Between two of your customers | Customer-to-customer payment |
| `INTERNAL_REALLOCATION` | Between two pockets of the same customer | Moving a customer's own money |


Funding and defunding carry an extra descriptive field — `source` on funding, `target` on defunding — recording where the money came from or went to on your own side. Free text up to 200 characters. It is your reference; Jiko does not interpret it.

### Reallocation has two flavors

`INTERNAL_REALLOCATION` takes a `transfer_type`:

- **`BANK_TRANSFER`** (default) — sells holdings in the origin pocket and buys new holdings for the destination.
- **`SECURITY_TRANSFER`** — moves the securities directly between pockets with no bank transaction. Instant, and currently limited to JikoPay pockets.


## Addressing the far end

How you identify the destination depends on the type.

**Funding, defunding and internal reallocation** address a pocket directly:

```json
"to_account": { "id": "<pocket_id>", "type": "JIKO_ACCOUNT" }
```

**Peer-to-peer** addresses an On-Us counterparty:

```json
"to_account": { "id": "<counterparty_id>", "type": "COUNTERPARTY" }
```

The sending customer registers the recipient by their Jiko network address — the account number of a virtual bank account portal that carries the `ON_US` rail — and Jiko verifies it by **name match** against the account holder:

```
POST /api/v2/customers/{customer_id}/counterparties/
```

with `type: "on_us"`, the recipient's `account_number`, and a `name_match` verification carrying the recipient's `legal_name`.

Get both values from the recipient portal's funding instructions:

```
GET /api/v2/pockets/{pocket_id}/portals/{portal_id}/funding-instructions/
```

The `ON_US` instruction returns `account_number` (the Jiko network address) and `legal_name`. Pass both to the sender — **a name mismatch prevents the counterparty being created**, and the error at that point is about the name, not the account.

A portal only carries `ON_US` if the pocket is JikoPay. Read the portal's `payment_rails` rather than assuming.

Two things are rejected at registration: a portal that is not `OPEN` or does not allow `ON_US`, and a portal belonging to the registering customer themselves. Use `INTERNAL_REALLOCATION` to move a customer's money between their own pockets.

### Workflow, for a peer-to-peer transfer

Partner systems:

1. Ask the recipient for their Jiko network address. It comes from the `ON_US` funding instruction on their portal: an `account_number` and a `legal_name`.
2. Register it against the **sending** customer with `type: "on_us"` and a `name_match` verification carrying that exact legal name.
3. Wait for `counterparty.status.linked`.
4. Create the transfer with `type: "PEER_TO_PEER"`, `async_mode: true`, and `to_account` addressing the counterparty.
5. Track it by `on_us_transfer_id`, which both ends share.


Funding, defunding and internal reallocation skip steps 1–3 — they address a pocket by ID and need no counterparty.

### Relevant API endpoints

| Step | Purpose | Endpoint |
|  --- | --- | --- |
| 1 | Read the recipient's `ON_US` address and legal name | GET `/api/v2/pockets/{pocket_id}/portals/{portal_id}/funding-instructions/` |
| 2 | Register the recipient as an On-Us counterparty | POST `/api/v2/customers/{customer_id}/counterparties/` |
| 3 | Check its status | GET `/api/v2/customers/{customer_id}/counterparties/{counterparty_id}/` |
| 4 | Dry-run a security-transfer reallocation | POST `/api/v1/transfers/on-us/quotes/` |
| 5 | Create the transfer | POST `/api/v1/transfers/on-us/` |
| 6 | Read it back from either side, where both ends are yours | GET `/api/v1/transfers/on-us/{transfer_id}/` |


## Specifying the amount

Two forms are accepted, discriminated on `amount.type`:

- **`REQUESTED_AMOUNT`** — a specific amount in USD cents (`amount_usdc`).
- **`FULL_WITHDRAWAL`** — liquidates all holdings in the source pocket and moves the proceeds.


`FULL_WITHDRAWAL` is available on defunding, peer-to-peer and internal reallocation. It is **not** valid for `PARTNER_CUSTOMER_FUNDING`.

Use `FULL_WITHDRAWAL` rather than reading a balance and sending it as a requested amount — it avoids the race between the two calls, and the source pocket's balance is invested, not idle cash.

> The top-level `amount_usdc` field on the request body is deprecated in favor of the `amount` object. New integrations should send `amount`.


## Synchronous and asynchronous

The request takes an `async_mode` flag, defaulting to `false`.

**Use `async_mode: true`.** Jiko accepts the instruction, returns immediately with the transfer in `PENDING`, and reports progress through webhooks. With `async_mode: false` the call blocks until the transfer resolves, which ties your request to Jiko's processing time and makes timeouts your problem to reconcile.

## Quotes

```
POST /api/v1/transfers/on-us/quotes/
```

A quote is a dry run of a **security-transfer internal reallocation**: the same validation and the same ruleset evaluation as the real thing, but nothing is booked and nothing is persisted. It returns:

| Field | Meaning |
|  --- | --- |
| `is_allowed` | Whether the transfer would be permitted at evaluation time |
| `rejection_reason` | Partner-facing reason when `is_allowed` is false, otherwise null |
| `rejection_detail` | Human-readable explanation, otherwise null |
| `settlement_type` | The settlement the transfer would receive, for example `T+0` or `T+1` |
| `eligible_transfer_amount` | Maximum the customer is eligible to move given their short-maturity holdings. Zero when the request was rejected before holdings could be evaluated |


Only `type: "INTERNAL_REALLOCATION"` with `transfer_type: "SECURITY_TRANSFER"` is quotable. Funding, defunding, peer-to-peer and bank-transfer reallocation are rejected with `422`.

A successful quote is **indicative**. It is not a guarantee that the transfer will book.

## Lifecycle

| Status | Meaning |
|  --- | --- |
| `PENDING` | Accepted, in progress |
| `COMPLETED` | Both legs posted |
| `REJECTED` | Not processed |


A rejection carries a `reason`: `INSUFFICIENT_FUNDS`, `ACCOUNT_UNAVAILABLE`, `INVALID_TRANSFER`, `INVALID_CURRENCY`, `SANCTION_SCREEN_FAILED` or `CANCELED`.

The transfer resource also returns a `fees` list. Fees are a distinct posting against the pocket and are never netted against the transfer amount.

## Webhooks

To the **originating** side:

| Event | Meaning |
|  --- | --- |
| `transfers.on-us.processing` | Instruction accepted and in progress |
| `transfers.on-us.success` | Transfer completed |
| `transfers.on-us.rejected` | Transfer rejected |


Payload: `on_us_id`, `origin_account_id`, `destination_account_id`.

To the **receiving** side:

| Event | Meaning |
|  --- | --- |
| `transfers.on-us.received` | Funds credited to the receiving pocket |


Payload: `on_us_id`, `receiving_pocket_id`, `transaction_activity_id`.

That is the most complete payload of any rail — the resulting transaction is addressable directly, with no search of the feed.

You receive both sets of events for a peer-to-peer transfer only when both ends are your own customers. Where the recipient belongs to another partner, you get the originating events and their partner gets `received`.

## Endpoints

| Operation | Endpoint |
|  --- | --- |
| Create a transfer | `POST /api/v1/transfers/on-us/` |
| Quote a security transfer | `POST /api/v1/transfers/on-us/quotes/` |
| Get a transfer | `GET /api/v1/transfers/on-us/{transfer_id}/` |


The create request is discriminated on `type` and accepts:

- `transfer_id` — client-generated UUID for idempotency
- `end_to_end_identification` — up to 35 characters
- `description` — up to 100 characters


`GET /api/v1/transfers/on-us/{transfer_id}/` resolves from either side of a transfer where both ends are yours. It returns the transfer's type, amount, status, rejection reason where applicable, and any fees.

## Reading the money

Both legs appear in the transaction feed as `type: "ON_US"`:

- `on_us_transfer_id` — the transfer, shared by both sides
- `on_us_transfer_type` — `PEER_TO_PEER_TRANSFER`, `INTERNAL_REALLOCATION` and so on
- `counterparty_name` — the party at the other end
- `associated_pocket_id` — the pocket at the other end
- `end_to_end_identification` — the sender's reference, visible to the recipient
- `direction` — `DEBIT` on the sending pocket, `CREDIT` on the receiving one


Filter with `filter[on_us_transfer]` to resolve a transfer ID to its transactions, or `filter[type]=ON_US` for the rail.

## Tracing

JikoNet is the simplest rail to trace. `on_us_transfer_id` is a single identifier shared by both ends and present on the transfer resource, on both transactions, and on every webhook. Where both ends are your own customers you can see the complete transfer from either side, which no other rail offers. Where the recipient belongs to another partner you see your own leg only, as on any external rail.

Where the sender populates `end_to_end_identification`, that reference travels with the transfer and is visible to the recipient — the closest thing Jiko offers to a payer-supplied reference both parties agree on in advance.

## See also

- [Create On-Us transfer](/products/partner-api/reference/on-us-transfers/create-on-us-transfer) — full request schema
- [Counterparties](/products/partner-api/reference/counterparties-v2/create_counterparty_api_v2_customers__customer_id__counterparties__post)
- [Portals and funding instructions](/products/partner-api/reference/portals-v2/portal-list-funding-instructions)
- [Webhooks](/products/partner-api/guides/building/webhooks)