BIP Implementation Notes

Companion to: yona:ruleset:v1.0 and the Base Interoperability Profile (BIP)

Document: Implementation Notes (non-normative)

Purpose: practical guidance for teams implementing BIP-conformant behavior. This page does not add, remove, or restate normative requirements; where there is any conflict, follow the YONA Ruleset, the BIP, and the BIP Conformance Test Suite.

License

Copyright © 2026 YONA LLC.

Text and explanatory content in this document are licensed under the Creative Commons Attribution 4.0 International License (CC BY 4.0).

License texts: CC BY 4.0

1. About This Page

1.1 Non-normative status

Unlike the BIP and the conformance suite, this page uses everyday language and recommendations (consider, typically, one approach). It is safe to treat the entire document as informative unless you are reading a direct quotation from another YONA document linked here.

1.2 Not an authoritative blueprint

No code structure, database schema, or operational policy on this page is required for conformance. Use what fits your stack, threat model, and release process; validate outcomes against the normative documents and your chosen test matrix.

2. How to Use the Document Set

2.1 Suggested reading order

  1. YONA Ruleset 1.0 — message payloads, fields, and ruleset semantics.
  2. Base Interoperability Profile (BIP) did:web discovery, required services, HTTPS + JOSE transport, endpoint behavior, conformance scope.
  3. Reference Messages & DID Examples — end-to-end sequences, canonical JSON shapes, DID publication patterns, and a concise "drift" checklist.
  4. BIP Conformance Test Suite — what a harness is likely to assert, including invalid families, replay, and byte-exact hashing fixtures.

2.2 When to lean on the conformance suite

When your question is "is this HTTP status / body combination allowed?" or "must I reject this malformed field with a signed REJECT or with no YONA body?", answer it from the BIP and the suite's matrix, not from example code. The suite is deliberately precise about bindable vs unbindable failures, replay windows, and terminal responses.

3. Suggested Implementation Phases

Many teams reduce risk by separating concerns into layers that can be tested independently.

3.1 Phase A — Cryptography and messages

  • Build, sign, and verify compact JWS for each message_type you need.
  • Centralize payload construction so ruleset_id, TTLs, and field names stay consistent.
  • Unit-test request_jws_sha256 against published byte-exact fixtures (Section 9).

3.2 Phase B — DID and HTTP surface

  • Resolve counterparty did:web documents; select YonaPaymentIntentService and YonaAuthorizationService endpoints from service entries.
  • Expose your own HTTPS handlers that accept POST with Content-Type: application/jose and honor Accept: application/jose on the client side.

3.3 Phase C — Flows and state

  • Implement pull-payment (retrieve intent → authorize with embedded intent) and/or push-payment paths.
  • Add persistence and idempotency policies for jti, intent rows, and repeated yona.authorization_request handling (Section 7).

3.4 Phase D — Conformance and interop

  • Run the matrix cases relevant to your claimed role (originator client, beneficiary server, or both).
  • Capture evidence per your governance process (BIP discusses conformance evidence at a high level).

4. Cryptography and JWS Practice

4.1 Headers, payloads, and JSON

  • Use Ed25519 with a protected header consistent with your DID document (alg, typ, and a kid that resolves in the issuer DID document).
  • Remember the BIP rule: evaluate messages as received — avoid normalizing JSON (key reordering, pretty-printing) between verification and hashing steps.
  • When generating payloads, pick one JSON serialization strategy (commonly stable key order or library default) and use it everywhere so signatures are reproducible in tests.

4.2 request_jws_sha256

The response binds to the exact authorization request compact JWS string (ASCII bytes), not to a canonicalized parse tree. Hash the raw request body your verifier used, then base64url-encode the SHA-256 digest. Mix-ups here are a frequent interop breaker; the conformance suite includes dedicated coverage.

4.3 Duplicate JSON members and parsing

Duplicate object keys are invalid. If your JSON parser silently picks a winner, you may pass local tests yet fail conformance. Prefer a parser that rejects duplicates, or add a raw-content check as required by the BIP.

5. DID Resolution and Service Discovery

5.1 Caching and rollout

Production systems usually cache DID documents for a few minutes to balance load and freshness. Plan key rotation with an overlap window (see the key-rotation pattern in Reference Messages Section 4.7).

Local development with did:web often uses HTTP for localhost; production endpoints should follow the BIP HTTPS requirements.

5.2 Verifying the signing key (kid)

A robust verifier loads the issuer DID document, checks that the JWS kid refers to a verification method authorized for assertion (per your ruleset/DID profile), imports the public JWK, then verifies the compact JWS. Skipping the authorization graph and trusting only the bare key document opens avoidable ambiguity during key rotation.

6. Flow-Specific Guidance

6.1 Pull-payment

  • Treat yona.retrieve_intent as a keyed lookup: the locator is not a substitute for the signed yona.payment_intent.
  • After retrieval succeeds, the originator builds a pull-style yona.authorization_request that embeds the exact beneficiary-signed payment intent JWS.
  • A retrieval failure is not an authorization decision; do not map it to ACCEPT, REJECT, or NO_RESPONSE semantics (see BIP Section 5.1).

6.2 Push-payment

  • Push requests carry beneficiary_handle, payment_terms, and intended_asset_type; there is no yona.payment_intent retrieval step.
  • Keep the handle opaque at the originator: it is a beneficiary-local reference, not a general-purpose payment URI.

7. State, Idempotency, and Replay

7.1 jti and repeated requests

The ruleset and suite use jti freshness and repeated-request semantics to block replays and to define how retries behave. Decide where your system records jti (authorization service, payment-intent service, or both) and how long entries live relative to message exp.

For yona.authorization_request, many implementations also need a policy for "same intent_id, new network retry" versus "duplicate with changed material" — the conformance suite encodes expectations you should mirror rather than inventing ad hoc rules.

7.2 Binding embedded pull intents

For pull-payment, compare the embedded yona.payment_intent to what your beneficiary system considers authoritative (amount, currency, acceptable assets, locator). If a client replays an authorization with different embedded material for the same stored intent, treat that as a policy violation, not a silent success.

8. HTTP Status Codes Versus YONA Bodies

A recurring implementation gap is assuming every error returns JSON or every denial returns HTTP 4xx. Under BIP, YONA terminal messages are HTTP 200 + application/jose bodies; some failure modes explicitly require no YONA response body.

8.1 Authorization endpoint

When the beneficiary can construct a bound terminal response (including deterministic validation failures), the BIP expects a signed yona.authorization_response with ACCEPT or REJECT. When binding inputs are missing or the body is unparseable in ways the profile forbids, the server must not emit a YONA message (see BIP Section 5.2).

8.2 Payment-intent retrieval

The payment-intent endpoint never returns yona.authorization_response. If you cannot return a verified yona.payment_intent, return a non-YONA HTTP outcome; clients must treat that as retrieval failure, not authorization.

9. Testing Workflow

9.1 Fixtures and golden vectors

Start from the suite's published fixtures for request_jws_sha256 and wrong-binding cases. Add your own golden tests for message builders so refactors do not silently change byte sequences.

9.2 Roles under test

Clarify whether you are implementing the originator client, the beneficiary server, or both. The suite names roles explicitly; half-port implementations often pass local mocks yet fail cross-VASP interop because only one side was exercised.

10. Interoperability Checklist

  • ruleset_id is exactly yona:ruleset:v1.0 everywhere.
  • DID service types are spelled YonaPaymentIntentService and YonaAuthorizationService.
  • Pull uses acceptable_asset_types; push uses intended_asset_type.
  • beneficiary_handle matches the normative did=…;alias=… pattern.
  • request_jws_sha256 is computed from the exact compact JWS bytes you received.
  • Your HTTP client sends Accept: application/jose on YONA calls.
  • Optional DID services (travel rule, settlement, assurance) never change core authorization semantics.

11. Pitfalls and Field Drift

The Reference Messages document ends with a focused list of common drift points (hashing, retrieval vs authorization, mixed invalid cases, handle form, field names, optional services). Start there when debugging a counterparty mismatch:

Reference Messages — §6.1 Common drift points

Also read §6.2–§6.4 for pull vs push reminders and optional service boundaries — they are short and align tightly with BIP intent.

12. Illustrative Patterns (Non-Authoritative)

The following patterns appear in real codebases because they separate concerns cleanly. They are suggestions only; your architecture may differ.

12.1 Module boundaries

  • Message builders — functions that only assemble JSON payloads and shared claims (iat/exp, jti, ruleset_id).
  • JWS helpers — sign/verify compact JWS and compute request_jws_sha256.
  • Validators — schema-style checks per message_type, including pull vs push classification.
  • DID resolution — HTTP fetch of did.json, service selection, key lookup by kid, optional cache.
  • HTTP routes — thin adapters that enforce content types, call validators, and map outcomes to HTTP + JOSE responses per BIP.

12.2 Example concerns from a pilot codebase

An internal pilot implementation (not part of this website) structured beneficiary endpoints roughly as: verify the request JWS using the originator's DID document; validate common claims and message shape; record jti to block replays; persist intent state; and for authorization retries, compare material fields before echoing a prior ACCEPT/REJECT. That layout is one way to keep cryptographic verification, business rules, and storage from tangling — it is not a normative requirement and may not match your compliance or scaling needs.