A JikoNet transfer — also known as an On-Us transfer in the API — is the easiest way to send cash directly between two Jiko pockets. Nothing touches an external network, so there is no cut-off, no return window and no clearing delay.
- Build a peer to peer payment network like venmo
- Debit and Credit your users Jiko pockets
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.
- JikoPay pockets at both ends. A portal on a JikoStore pocket does not carry the
ON_USrail. Read the portal'spayment_railsrather than assuming, and confirm with your Jiko point of contact which pocket types your partnership can open. - Approved customers and pockets in
OPENstatus 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_accountorto_account. Without one,PARTNER_CUSTOMER_FUNDINGandPARTNER_CUSTOMER_DEFUNDINGhave no near end. - An
on_uscounterparty inLINKEDstatus, for peer-to-peer. Registered from the recipient portal'saccount_numberand the account holder's exactlegal_name. The recipient portal must beOPEN, must carryON_US, and must not belong to the registering customer — a customer moving money between their own pockets usesINTERNAL_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_TRANSFERis currently limited to JikoPay pockets. - Balance that can actually move. Use
FULL_WITHDRAWALwhere you mean "everything", rather than reading a balance and sending it back as a requested amount. - A webhook subscription, since the recommended
async_mode: truereports progress only through events:transfers.on-us.processing,transfers.on-us.successandtransfers.on-us.rejectedon the originating side,transfers.on-us.receivedon the receiving side. Subscriptions are recorded against the API user that creates them.
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.
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.
How you identify the destination depends on the type.
Funding, defunding and internal reallocation address a pocket directly:
"to_account": { "id": "<pocket_id>", "type": "JIKO_ACCOUNT" }Peer-to-peer addresses an On-Us counterparty:
"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.
Partner systems:
- Ask the recipient for their Jiko network address. It comes from the
ON_USfunding instruction on their portal: anaccount_numberand alegal_name. - Register it against the sending customer with
type: "on_us"and aname_matchverification carrying that exact legal name. - Wait for
counterparty.status.linked. - Create the transfer with
type: "PEER_TO_PEER",async_mode: true, andto_accountaddressing the counterparty. - 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.
| 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}/ |
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_usdcfield on the request body is deprecated in favor of theamountobject. New integrations should sendamount.
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.
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.
| 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.
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.
| 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 idempotencyend_to_end_identification— up to 35 charactersdescription— 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.
Both legs appear in the transaction feed as type: "ON_US":
on_us_transfer_id— the transfer, shared by both sideson_us_transfer_type—PEER_TO_PEER_TRANSFER,INTERNAL_REALLOCATIONand so oncounterparty_name— the party at the other endassociated_pocket_id— the pocket at the other endend_to_end_identification— the sender's reference, visible to the recipientdirection—DEBITon the sending pocket,CREDITon 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.
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.
- Create On-Us transfer — full request schema
- Counterparties
- Portals and funding instructions
- Webhooks