Submission routing rules
Outcome
Every outbound transaction (claim, eligibility, auth, status inquiry) routes to the correct trading partner deterministically — and when the routing produces an unexpected pick, you can use the precedence simulator to see exactly which rule fired and why.
Prerequisites
| Scope | What it lets you do |
|---|---|
edi.routing.read | View rules + run the simulator |
edi.routing.write | Add / edit / delete rules |
A trading partner registered with the relevant outbound capability (2.4 — Capabilities).
What a routing rule is
A routing rule says for transactions matching X conditions, send to partner Y via companion guide Z. Conditions narrow the rule's scope:
| Condition | Example |
|---|---|
| Transaction type | 837P, 837I, 270, 278, 276, 835-direction (rare) |
| Direction | outbound, inbound |
| Payer | A specific registered payer, or any |
| Program | A specific program, or any |
| State | OH, MI, or any |
| Submitter NPI | A specific provider, or any |
| Tag | Free-form tag — used for "test" partners, "dr" disaster-recovery, etc. |
Precedence
Rules are evaluated by specificity score:
score = sum(condition weights of conditions that match)
Weights from highest to lowest specificity:
| Condition | Weight |
|---|---|
| Submitter NPI | 64 |
| Program | 32 |
| Payer | 16 |
| State | 8 |
| Direction | 4 |
| Transaction type | 2 |
| Tag | 1 |
The highest-scoring matching rule wins. Ties are broken by
created_at ascending — older wins (so a deliberate older rule is not
silently superseded by a newer one with the same specificity).
Source: apps/edi-gateway/src/service/routing-resolver.ts.
Steps to add a routing rule
Open
/routingin the edi-app. The list shows every active rule grouped by transaction type.Click
+ New ruleor click an existing rule to edit. The RoutingRuleEditPage opens.Fill the form:
Field Notes Transaction type Pick from the partner's enabled capabilities only. Direction outboundis the default.Conditions Pick conditions and values; leave blank for "any". Trading partner Restricted to partners with the chosen transaction capability. Companion guide Restricted to guides bound to the chosen partner + transaction. Tag Free text. Active Toggle. Use the Precedence simulator before saving. The simulator asks for the same conditions you'd see at runtime (payer, program, state, submitter NPI) and shows which rule would fire — including the rule you are currently editing.
Save. The rule is live immediately for new outbound traffic.
The precedence simulator
The Precedence simulator at /routing is a backed-by-the-real-resolver
debugger. Source: POST /routing/resolve/explain on edi-gateway.
The simulator returns:
| Field | Content |
|---|---|
| Selected rule | The winner — partner, companion guide, score. |
| All candidates | Every rule whose conditions matched, sorted by score descending. |
| Why others lost | Per losing rule, which conditions matched / didn't and the resulting score. |
Common routing patterns
Single clearinghouse, all payers
rule:
tx_type: 837P
direction: outbound
partner: change-healthcare
The simplest pattern — every 837P goes to a clearinghouse, which then sub-routes to the right payer.
Direct submission for one payer, clearinghouse for others
rule_a:
tx_type: 837P
direction: outbound
payer: ohio-medicaid
partner: ohio-mits-direct
companion_guide: ohio-mits-2026q1
rule_b:
tx_type: 837P
direction: outbound
partner: change-healthcare
Rule A wins for Ohio Medicaid (specificity 16+2 = 18). Rule B wins for all others (specificity 2).
Per-state direct submission
rule:
tx_type: 837P
direction: outbound
state: OH
partner: ohio-mits-direct
Score 8+2 = 10. Pairs with a less-specific catch-all.
Program-specific routing
rule:
tx_type: 837P
direction: outbound
program: idd-waiver-ohio
partner: ohio-mits-direct
companion_guide: ohio-mits-idd-2026q1
Score 32+2 = 34. Wins over generic state-level rules.
Steps to debug a misrouted transaction
A transaction that went to the wrong partner:
Open the transaction at
/transactions/:id. Note the partner that received it and the timestamp.Open
/routing→ Precedence simulator. Enter the same conditions the transaction had (transaction type, payer, program, state).The simulator shows the current winner. Compare to what the transaction actually used.
If the winner has changed, look at the rule edit history. Most common: someone added a new more-specific rule or activated a tag.
Fix the rule that should have fired (re-tighten conditions or deactivate the conflicting rule). New transactions route correctly immediately; the misrouted one needs replay (see 8.2 — Replay & retry).
Validation
| Check | Expected |
|---|---|
New rule visible at /routing | Yes. |
| Simulator picks the new rule when conditions match | Yes. |
| Outbound transactions route to the new rule's partner immediately | Yes; no service restart needed. |
Audit log carries routing.create row | Yes. |
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Save returns "partner does not have this capability" | Partner's capability set excludes this transaction | Enable on the partner (2.4 — Capabilities). |
| Two rules tie on score and the wrong one wins | Older created_at wins by tiebreak | Add a more-specific condition to one of them. |
| Outbound stalls "no routing rule" | No active rule covers the transaction's conditions | Add a rule; or temporarily expand an existing rule's conditions. |
| Simulator says rule X wins but real traffic uses Y | Rule X was activated after the transaction was already in flight | Replay the transaction. |