Simulator
A local FedNow Service simulator: POST a pacs.008 customer credit transfer, receive the pacs.002 advice the FedNow Service would send — under scenarios you control, including the one that hurts in production (no answer at all).
v0 speaks HTTP (dev mode). An MQ-compatible interface is planned; the scenario engine is shared.
Quickstart
Section titled “Quickstart”cargo run -p fednow-sim# in another shell: generate a valid pacs.008 and send itcargo run -p fednow-core --example build_pacs008 > /tmp/pacs008.xmlcurl -s -X POST --data-binary @/tmp/pacs008.xml \ -H "content-type: application/xml" http://localhost:8080/fednow/messagesThe response is a pacs.002 ACSC advice (accepted, settlement completed) that
fednow-core itself validates as direction-clean.
Docker:
docker build -f simulator/Dockerfile -t fednow-sim .docker run -p 8080:8080 fednow-simScenarios
Section titled “Scenarios”Priority: config file → amount trigger → default.
| Trigger | Scenario | Advice |
|---|---|---|
| default | settle | ACSC + acceptance time + effective settlement date |
amount ends .11 |
reject | RJCT reason AC04 |
amount ends .22 |
accept without posting | ACWP |
amount ends .33 |
timeout | none — HTTP 202, no pacs.002 |
amount ends .44 |
delayed settle | ACSC after 2 s |
amount ends .55 |
reject by the service | RJCT proprietary reason E990 (vs .11’s participant reject) |
amount ends .66 |
ACWP + follow-up | ACWP now; ACCC follow-up queued, retrieved with a pacs.028 |
| profile-invalid message | always rejected | RJCT proprietary reason SIMV, violated rule codes in AddtlInf |
Each trigger maps to an official Customer Testing Program scenario — see the zero-to-CTP chapter.
Config file (fednow-sim.toml or FEDNOW_SIM_CONFIG), keyed by creditor-agent
routing number — see fednow-sim.toml.example.
Actions: settle, accept-without-posting, reject (+ reason), timeout,
delay (+ delay_ms). The real service’s technical error codes will replace
SIMV once the Technical Specifications are available (issue #14).
Timeout reconciliation — the point of this simulator
Section titled “Timeout reconciliation — the point of this simulator”A timed-out payment is unresolved, not failed: internally it still settled; your sender just never heard it. The simulator keeps an advice ledger for every processed payment, and a payment status request (pacs.028) — posted to the same endpoint, like on the real MQ channel — returns the withheld advice:
# 1. Send a pacs.008 with an amount ending in .33 → HTTP 202, no advice.# 2. Ask what happened:curl -s -X POST --data-binary @pacs028.xml \ -H "content-type: application/xml" http://localhost:8080/fednow/messages# → the ACSC advice: it settled all along. A blind resend would have paid twice.Unknown original message id → HTTP 404. The full walkthrough lives in the
FedNow Integration Handbook chapter on timeout reconciliation (docs/handbook/).
MQ mode — the real connection’s semantics
Section titled “MQ mode — the real connection’s semantics”The production FedNow connection is an IBM MQ queue pair, and it is asynchronous: a send returns nothing; advices arrive later on your receive queue, wrapped in the FedNow technical envelope with a Business Application Header. MQ mode mirrors exactly that:
# PUT: fire-and-forget send of a FedNowIncoming envelope → 202, empty bodycurl -s -X POST --data-binary @envelope.xml \ -H "content-type: application/xml" \ http://localhost:8080/mq/participants/991000009/send
# GET: next FedNowOutgoing envelope from your receive queue (204 when empty)curl -s http://localhost:8080/mq/participants/991000009/receiveDifferences from the HTTP dev mode, all deliberate:
- Every outcome is asynchronous — even profile-validation rejections
(
RJCT/SIMV) arrive as queued advices, not HTTP errors. - The post-ACWP follow-up status (
.66trigger) is pushed to the queue ~500 ms later; no pacs.028 needed (the HTTP mode cannot push). - A timeout (
.33) leaves the queue empty — poll all you want, nothing comes until a pacs.028 (sent through the same/send) replays the withheld advice.
Scenario triggers, config file and the advice ledger are shared between modes.
Endpoints
Section titled “Endpoints”| Method | Path | Purpose |
|---|---|---|
| POST | /fednow/messages |
HTTP dev mode: pacs.008 → pacs.002 advice; pacs.028 → stored advice replay |
| POST | /mq/participants/{rtn}/send |
MQ mode: fire-and-forget FedNowIncoming (pacs.008, pacs.028) |
| GET | /mq/participants/{rtn}/receive |
MQ mode: destructive get of the next FedNowOutgoing |
| GET | /healthz |
liveness |
State is in-memory and per-process (v0): restart forgets past payments and queued advices.
Pacsmith is an independent open-source project. Not affiliated with, endorsed by or sponsored by the Federal Reserve. FedNow is a service mark of the Federal Reserve Banks.