# Connect once, reach many: how a PSP joins a payment network

> What it takes for a PSP, bank or mobile money operator to join Ultraner Network: sandbox keys, a certification suite, a human review, then live traffic.

Published 2026-10-12 by the Ultraner team. Topic: connect. Tags: network, onboarding, certification, protocol.
Canonical: https://ultraner.com/blog/connect-once-reach-many

Every integration your team has built so far probably started the same way: a contract, a PDF of API docs, six weeks of building, and a reconciliation file format nobody else uses.

Then you did it again for the next partner.

The promise of a network is that you do it once. You implement one contract, prove it works, and from then on every other participant on the network is reachable through it. This piece walks through what that "once" actually involves on Ultraner Network, step by step, without the brochure.

## The shape you are joining

A gateway sits between a merchant and a rail: `merchant -> gateway -> rail`. A network sits between participants: `Network A -> Ultraner Network -> Network B`. You do not integrate with Ultraner to reach Ultraner's customers. You integrate to reach every other participant, and they reach you.

Participants are their own kind of entity. A mobile money operator, a bank, a fintech or a PSP joining the network gets its own identity, its own credentials and its own entry in the network directory. It is not a merchant account with extra permissions. That separation matters for trust: a compromised merchant API key can never be used to impersonate a network participant, because they are different credentials in a different system.

The architecture is on the [network overview](/network). The protocol itself is on the [protocol page](/network/protocol).

## Step 1: sandbox, immediately

A new participant gets sandbox credentials straight away, with no approval queue. Sandbox is a full copy of the network's behaviour, with simulated participants on the other side. You can resolve addresses, request quotes, authorize and execute payments, receive callbacks and watch settlement windows form, all without touching real money.

Mode belongs to the credential, not to the participant. An operator already carrying live traffic keeps its sandbox key too, because live participants still need to test changes.

## Step 2: speak the protocol

The message set is small on purpose:

| Message | What it does |
|---|---|
| `directory.resolve` | Who is at this address, in which country and currency, and which rails can reach it |
| `quote.create` | Price a payment before committing: rate, fee, what the sender pays, what the recipient receives |
| `payment.authorize` | Commit to a live quote |
| `payment.execute` | Move the authorized payment to processing |
| `payment.status` | Poll state (callbacks are primary) |
| `payment.reverse` | Undo an authorized payment that has not settled |
| `payment.refund` | Return funds for a settled payment |
| `callback` | Signed state-change push from the network to you |

Every request carries a participant ID, a timestamp, a single-use nonce, an HMAC-SHA256 signature over timestamp, nonce and body [3], and an idempotency key on anything that changes state. A replayed key with the same body returns the original result. A replayed key with a different body is rejected with a conflict. A reused nonce inside the five-minute window is rejected as a replay.

None of that is novel, and that is the point. The BIS roadmap for cross-border payments calls out inconsistent message formats and weak data standards as a core source of friction [1], and the industry's direction of travel is toward shared, structured standards such as ISO 20022 [2]. Our protocol describes financial intent (who, to whom, how much, why) and never a specific rail's quirks, so it can map onto those standards rather than compete with them.

### Quote before payment is not optional

The rule that most changes how participants build: `payment.authorize` is illegal without a live, unconsumed quote. The quote locks the FX rate and the fee for a short window. Authorize after it expires and you get `QUOTE_EXPIRED`, and you re-quote. A quote can be consumed once.

This removes a whole category of argument. The sender knew what the recipient would get before anything moved, and the network never silently reprices.

## Step 3: certification

Before production credentials exist, a participant passes a fixed suite of certification transactions against the network's simulator:

- a successful payment
- insufficient funds
- a timeout
- a reversal
- a refund
- malformed request handling
- idempotency replay handling
- signature failure handling

Each test has a pass or fail criterion. Production credentials cannot be requested until every one is green. Certification always runs in sandbox, so re-certifying after a change is routine, not an incident.

> Most outages between payment partners are not exotic. They are a timeout nobody handled, or a retry that charged twice. Certification tests exactly those.

## Step 4: a human says yes

Passing the tests is necessary, not sufficient. Compliance documents and a participant agreement covering the network rules are reviewed by a person. That step is deliberately never automated.

Production credentials are then scoped to the capabilities and currencies that were approved, not to everything.

## Step 5: monitored production

Once live, the network probes participant health continuously. A participant that fails health checks is excluded from routing automatically until it recovers: routing reads live health, not a cached list of what you said you could do. Every non-terminal transaction state has a maximum dwell time, after which it becomes `timeout` rather than hanging.

## What you get back

Implementing this once gets you:

- **Reach** to every participant the directory can resolve, without a bilateral contract for each.
- **One state machine** for every payment, with the network's reference kept distinct from your own.
- **One settlement position** per currency, netted across all counterparties, recorded at the moment each payment completes.
- **One error taxonomy**, so `ROUTE_NOT_FOUND` and `PARTICIPANT_UNHEALTHY` mean the same thing to everyone.

## Where we are, honestly

The participant model, directory, quotes, routing preview, payments, settlement windows, certification and the participant portal are built and running. Everything on the network today is sandbox. No participants are live, and settlement windows model and reconcile obligations rather than moving money between banks, which needs licensing and participant agreements first. The first real connectors are adapters behind a provider-neutral interface, built after the core was proven against simulators.

We think that order is the right one. A network that wires in its first big partner before its state machine is proven ends up shaped around that partner.

## If you want to try it

Start with the [protocol page](/network/protocol) and check it against your own systems: can you produce an idempotency key per payment intent, sign requests, and honour a quote expiry? If yes, the [connect page](/network/connect) is the next step. If you also want to accept payments from merchants today, that is a different product, documented under [docs](/docs).

## Sources

[1] Enhancing cross-border payments: building blocks of a global roadmap, BIS Committee on Payments and Market Infrastructures. https://www.bis.org/cpmi/publ/d193.htm
[2] ISO 20022 financial services messaging standard, ISO 20022 Registration Authority. https://www.iso20022.org/
[3] RFC 2104: HMAC, Keyed-Hashing for Message Authentication, IETF. https://www.rfc-editor.org/rfc/rfc2104
