From 3e058e5fbf20d38ac36e27d84166bf1df9e6b864 Mon Sep 17 00:00:00 2001 From: Marcel Ebert Date: Wed, 7 Oct 2026 16:57:11 +0200 Subject: [PATCH] docs(repo): tidy the Monerium B2B docs wording --- docs/README.md | 2 +- docs/adr-0005-monerium-b2b-onramp.md | 4 +- docs/operations-monerium-b2b-rollout.md | 8 +- docs/operations-monerium-b2b-runbook.md | 16 +-- docs/product-monerium-b2b-flow.md | 158 ++++++++++++------------ 5 files changed, 94 insertions(+), 94 deletions(-) diff --git a/docs/README.md b/docs/README.md index 1928eee29..a00c7e796 100644 --- a/docs/README.md +++ b/docs/README.md @@ -33,7 +33,7 @@ The smaller set of general project documents stays directly in `docs/`: | [`operations-monerium-interface.md`](operations-monerium-interface.md) | Monerium onramp boundary across the OAuth and white-label apps plus the profile, address, IBAN, and payment interface reference | | [`operations-testing.md`](operations-testing.md) | Maintained test strategy and suite boundaries | | [`product-dashboard.md`](product-dashboard.md) | Current dashboard product scope and acknowledged gaps | -| [`product-monerium-b2b-flow.md`](product-monerium-b2b-flow.md) | High-level end-to-end flow of the Monerium B2B onramp for Vortex, SulPayments and Monerium, with the open questions per party | +| [`product-monerium-b2b-flow.md`](product-monerium-b2b-flow.md) | High-level end-to-end flow of the Monerium B2B onramp for Vortex, the partner and Monerium, with the open questions per party | | [`proposal-mcp-server.md`](proposal-mcp-server.md) | Active, non-authoritative discussion draft | | [`proposal-monerium-consumer-onramp.md`](proposal-monerium-consumer-onramp.md) | Phase-2 proposal for the consumer (Safe + passkey) Monerium onramp; the B2B variant shipped | | [`proposal-api-driven-kyc-kyb.md`](proposal-api-driven-kyc-kyb.md) | Proposal for API-driven verification using preserved provider-specific workflows | diff --git a/docs/adr-0005-monerium-b2b-onramp.md b/docs/adr-0005-monerium-b2b-onramp.md index d991a84cd..81a40250b 100644 --- a/docs/adr-0005-monerium-b2b-onramp.md +++ b/docs/adr-0005-monerium-b2b-onramp.md @@ -19,7 +19,7 @@ consumer-flow design this grew out of remains a phase-2 proposal: ## Context -Partner-sourced business clients (SulPayments' OTC corporates, KYB'd under the partner's +Partner-sourced business clients (the partner's OTC corporates, KYB'd under the partner's FINMA/VQF licence with per-customer reliance attestations to Monerium) need EUR → USDC on Ethereum with **zero Vortex-side interaction**: no app, no wallet ceremony, no digital signature. Onboarding is paperwork only. The single blocker in the consumer design was @@ -144,7 +144,7 @@ not yet deployed, so this replaced the flat fee before launch with no migration) ## Amendment 2026-09-17: whole-deposit settlement and the refund path -Product requirements from the partner (SulPayments): one USDC transfer per bank +Product requirements from the partner: one USDC transfer per bank payment, and an automatic refund of the exact EUR amount to the payer's bank account when a payment cannot be converted inside the promised window. Vortex holding the funds for that refund is agreed commercially. Decisions (the proposal that led here, diff --git a/docs/operations-monerium-b2b-rollout.md b/docs/operations-monerium-b2b-rollout.md index 1706c1e27..898681e93 100644 --- a/docs/operations-monerium-b2b-rollout.md +++ b/docs/operations-monerium-b2b-rollout.md @@ -27,7 +27,7 @@ verbal/Telegram statements; consolidate into the MSA or a side letter: 6. SEPA recall / fraud loss allocation after conversion+forwarding. 7. Per-IBAN suspension capability for incident response. 8. Corporate KYB mechanism for direct (non-reliance) clients — not needed for the - SulPayments pilot, still an MSA item. + partner pilot, still an MSA item. 9. Advance notice of any change to the EIP-1271 ownership/link message (and the recovery message): the forwarder whitelists their exact hashes, so an unannounced change fail-closes new onboarding. @@ -41,7 +41,7 @@ the subsidy vault (P13). **G3 — external contract audit.** Parameters are final (ADR); the internal reviews and the invariant suite are done, but this moves client funds. -**G4 — pilot.** SulPayments agreement signed (terms inputs below), reliance +**G4 — pilot.** Partner agreement signed (terms inputs below), reliance attestations per customer, 3–5 clients at **€50k/client/day** (paper control), launch fee policy 12.5 bps target / 15 bps floor (B1). @@ -89,7 +89,7 @@ The Sepolia sandbox follows its own procedure in the runbook (§8). Receive → "Simulate bank transfer") and re-verify the signed `webhook-id`, `webhook-timestamp`, and `webhook-signature: v1,` fixture against a real production delivery. -9. SulPayments side: manager profile configured (EU corridor, business type), secret +9. Partner side: manager profile configured (EU corridor, business type), secret credential issued, deposit-event webhook registered and verifying signatures against `GET /v1/public-key`. 10. Confirm every mapped forwarder has a zero EURe balance before the first enablement. @@ -199,7 +199,7 @@ The Sepolia sandbox follows its own procedure in the runbook (§8). | G1 package (9 items) | Marcel ↔ Monerium | All verbal; consolidate in writing | | G2 legal scope | Counsel | Not started | | G3 audit | External | After PR merge; params final | -| SulPayments agreement (terms above) | Marcel ↔ partner | Drafting inputs ready | +| Partner agreement (terms above) | Marcel ↔ partner | Drafting inputs ready | | Sandbox SEPA simulation + 3 TODO(sandbox) pins | Engineering (needs Marcel's sandbox login) | Open — only remaining engineering unknown | | Fee Safe multisig creation | Ops | Before implementation deploy; also the subsidy vault's treasury | | Reference wording in the partner agreement | Marcel ↔ partner | Agreement says "Coinbase EURC oracle"; implementation uses the Coinbase Exchange EURC-USDC bid/ask midpoint (spot, since 2026-09-18) — confirm that is what was meant | diff --git a/docs/operations-monerium-b2b-runbook.md b/docs/operations-monerium-b2b-runbook.md index be2112c79..1248616ef 100644 --- a/docs/operations-monerium-b2b-runbook.md +++ b/docs/operations-monerium-b2b-runbook.md @@ -887,7 +887,7 @@ On the `vortex-sandbox` service only: | Variable | Value | |---|---| | `FLOW_VARIANT` | `mykobo` (startup refuses B2B otherwise; the sandbox's retail EUR onramp then runs on Mykobo) | -| `MONERIUM_WHITELABEL_CLIENT_ID`, `MONERIUM_WHITELABEL_CLIENT_SECRET` | SulPayments' sandbox white-label app (S11) | +| `MONERIUM_WHITELABEL_CLIENT_ID`, `MONERIUM_WHITELABEL_CLIENT_SECRET` | The partner's sandbox white-label app (S11) | | `MONERIUM_B2B_RPC_URL` | Sepolia RPC | | `MONERIUM_B2B_FORWARDER_FACTORY_ADDRESS` | `$FACTORY` | | `MONERIUM_B2B_KEEPER_PRIVATE_KEY`, `MONERIUM_B2B_GUARDIAN_PRIVATE_KEY`, `MONERIUM_B2B_ATTESTOR_PRIVATE_KEY` | the three keys of §8.3 | @@ -896,7 +896,7 @@ On the `vortex-sandbox` service only: | `MONERIUM_B2B_WEBHOOK_SECRET` | `whsec_` plus base64 of 32 random bytes: `echo "whsec_$(openssl rand -base64 32)"` | | `MONERIUM_B2B_ENABLED` | `true`, set last | -Register Vortex's webhook subscription on SulPayments' sandbox app with the same +Register Vortex's webhook subscription on the partner's sandbox app with the same secret, from `apps/api` with that app's credentials and `MONERIUM_API_URL` pointing at Monerium's sandbox API: @@ -914,18 +914,18 @@ Restart the service. Startup fails if a required setting is missing; once it is ### 8.7 Partner and test clients -1. Make SulPayments' sandbox profile a manager: +1. Make the partner's sandbox profile a manager: `PUT /v1/admin/managed-profile-managers/` with corridor `EU` and customer - type `business`. SulPayments then takes a key from dashboard-sandbox and registers + type `business`. The partner then takes a key from dashboard-sandbox and registers its webhook through `POST /v1/webhook` (`DEPOSIT_UPDATED`, `ACCOUNT_UPDATED`). -2. Per test client, once SulPayments confirms the Monerium profile is approved: §1.2 +2. Per test client, once the partner confirms the Monerium profile is approved: §1.2 (refund address, deploy the clone), §1.4 (map), §1.5 (automatic link and IBAN), - §1.7 (activate). Until the destination endpoint (V6) exists, SulPayments sends the + §1.7 (activate). Until the destination endpoint (V6) exists, the partner sends the profile ID and the Sepolia destination to Vortex directly. ### 8.8 Test payments -SulPayments simulates each SEPA payment on the client's profile in its Monerium sandbox +The partner simulates each SEPA payment on the client's profile in its Monerium sandbox app ("Simulate bank transfer"); EURe lands on the clone and the keeper takes over. | Test | Payment | Expected | @@ -934,7 +934,7 @@ app ("Simulate bank transfer"); EURe lands on the clone and the keeper takes ove | Chunked | €60 | Three chunks at the €25 cap, then one forward of their sum | | Refund | €15 | Suspend the account before the payment (`PATCH /v1/admin/monerium-b2b/accounts//status` with `suspended`): the keeper converts nothing for a suspended account but still arms the clone's clock and runs recoveries. After two hours the deadline job marks the deposit, the keeper recovers it, and the refund leaves from the client's IBAN. Reactivate afterwards. If the simulated transfer carries no payer IBAN and name, the refund parks as `recovery_failed`; that is a finding about the sandbox simulation, closed with `PATCH /v1/admin/monerium-b2b/deposits//status` | -`DEPOSIT_UPDATED` reports every step to SulPayments, and `GET /v1/monerium-b2b/deposits` +`DEPOSIT_UPDATED` reports every step to the partner, and `GET /v1/monerium-b2b/deposits` shows the same snapshots. ### 8.9 Re-centre the pool before a session diff --git a/docs/product-monerium-b2b-flow.md b/docs/product-monerium-b2b-flow.md index 46f87229b..2b0444835 100644 --- a/docs/product-monerium-b2b-flow.md +++ b/docs/product-monerium-b2b-flow.md @@ -2,11 +2,11 @@ > **Status:** living overview, draft for alignment. Last updated 2026-10-01, including > Monerium's written answers and the call of 2026-09-30, and the KYB and sandbox -> decisions sent to SulPayments and Monerium on 2026-10-01. -> **Audience:** Vortex/SatoshiPay internally, SulPayments, and Monerium. -> **Scope:** the EUR to USDC onramp for SulPayments' business clients, as built for the +> decisions sent to the partner and Monerium on 2026-10-01. +> **Audience:** Vortex/SatoshiPay internally, the partner, and Monerium. +> **Scope:** the EUR to USDC onramp for the partner's business clients, as built for the > pilot on the branch of PR #1375. It is not merged or deployed yet. Open questions carry -> an ID such as **[M2]** (Monerium), **[S1]** (SulPayments) or **[V1]** (Vortex internal) +> an ID such as **[M2]** (Monerium), **[S1]** (partner) or **[V1]** (Vortex internal) > and are collected in [section 12](#12-open-questions), with space for the answers. > Changes proposed but not built yet are marked **Proposed**. Facts from Monerium's > public API spec (version 2.0.0) and guides are marked as such where Monerium has not @@ -30,7 +30,7 @@ ## 1. In one paragraph -A SulPayments business client sends EUR by SEPA to its own dedicated IBAN. Monerium +A partner's business client sends EUR by SEPA to its own dedicated IBAN. Monerium mints the same amount of EURe to a smart contract that Vortex deployed for that client, the **forwarder**. Vortex converts the EURe to USDC on chain at a price tied to a public market reference, and sends the whole payment to the client's wallet as **one USDC @@ -43,10 +43,10 @@ the two-hour window, the client's own refund wallet, which Vortex holds. | Party or component | Role | |---|---| -| **SulPayments** | Partner. Brings the business clients, owns the white-label app at Monerium in which their profiles live, performs and submits their KYB under its reliance agreement with Monerium, receives status webhooks, and hands each client its IBAN. | +| **Partner** | Partner. Brings the business clients, owns the white-label app at Monerium in which their profiles live, performs and submits their KYB under its reliance agreement with Monerium, receives status webhooks, and hands each client its IBAN. | | **Client** | The business that sends EUR and receives USDC in its own wallet, the **destination**. | -| **Monerium** | Licensed EURe issuer. Hosts each client's profile and IBAN in SulPayments' white-label app, mints EURe for incoming SEPA payments, and pays out EUR on redemption. | -| **Vortex / SatoshiPay** | Operator. Deploys the contracts, runs the **keeper** service that converts and forwards, runs refunds, and reports status. Uses SulPayments' white-label app credentials for everything after KYB. | +| **Monerium** | Licensed EURe issuer. Hosts each client's profile and IBAN in the partner's white-label app, mints EURe for incoming SEPA payments, and pays out EUR on redemption. | +| **Vortex / SatoshiPay** | Operator. Deploys the contracts, runs the **keeper** service that converts and forwards, runs refunds, and reports status. Uses the partner's white-label app credentials for everything after KYB. | | **Forwarder contract** | One per client on Ethereum. Receives the minted EURe, swaps it, holds the USDC until the payment is complete, then forwards it. | | **Subsidy vault** | A Vortex-funded USDC pool that tops up a swap when the market delivers less than the client's guaranteed floor. | | **Fee treasury** | Vortex multisig that receives the conversion fee. | @@ -76,7 +76,7 @@ flowchart LR subgraph Vx["Vortex"] KEEP["Keeper service"] end - SP["SulPayments"] + P["Partner"] CB -- "1 SEPA EUR" --> IBAN IBAN -- "2 mint EURe" --> FWD @@ -85,7 +85,7 @@ flowchart LR VAULT -. "top-up below floor" .-> FWD FWD -. "fee above target" .-> TREAS FWD -- "4 one USDC transfer" --> DEST - KEEP -- "status webhooks" --> SP + KEEP -- "status webhooks" --> P FWD -. "not converted in 2 h" .-> REC REC -. "refund EUR" .-> RED RED -. "SEPA refund" .-> CB @@ -98,80 +98,80 @@ subsidy on a swap, or the refund path. ### 4.1 What has to be true when onboarding ends -- The client has a **KYB-approved corporate profile** in SulPayments' white-label app at - Monerium, submitted by SulPayments under its reliance agreement. +- The client has a **KYB-approved corporate profile** in the partner's white-label app at + Monerium, submitted by the partner under its reliance agreement. - A **forwarder contract** exists with the client's destination wallet written into it. The destination cannot be changed later. A new wallet means a new forwarder and moving - the IBAN, on SulPayments' written instruction. + the IBAN, on the partner's written instruction. - The forwarder is **linked** to the client's Monerium profile, and the client's **IBAN points at the forwarder**. Monerium mints to whatever address the IBAN points at, so this is what routes every payment through the conversion. An IBAN pointing at the client's own wallet would deliver EURe, not USDC. - The client's **refund wallet** is linked to the client's profile as well, so a refund leaves from the client's own IBAN (section 8.3). -- Vortex has mapped the client under **SulPayments' partner account**, so webhooks and - API reads reach SulPayments. +- Vortex has mapped the client under **the partner's account**, so webhooks and + API reads reach the partner. ### 4.2 Proposed onboarding flow -SulPayments owns the white-label app at Monerium and submits each client's KYB there. -Monerium returns the new profile's ID, and SulPayments passes it to Vortex together with +The partner owns the white-label app at Monerium and submits each client's KYB there. +Monerium returns the new profile's ID, and the partner passes it to Vortex together with the client's destination wallet. Vortex does everything after KYB with the same app's credentials. ```mermaid sequenceDiagram autonumber - participant SP as SulPayments + participant P as Partner participant M as Monerium participant V as Vortex participant C as Ethereum participant CL as Client - SP->>M: Create the client profile in SulPayments' app - M-->>SP: Profile ID - SP->>M: Company details, form and verifications - SP->>V: Destination wallet for this profile ID [V6] - V->>M: Check the profile exists in SulPayments' app + P->>M: Create the client profile in the partner's app + M-->>P: Profile ID + P->>M: Company details, form and verifications + P->>V: Destination wallet for this profile ID [V6] + V->>M: Check the profile exists in the partner's app M-->>V: profile.updated, state approved V->>C: Deploy forwarder with destination and fee policy V->>M: Link forwarder and refund wallet to the profile V->>M: Request the IBAN for the forwarder M-->>V: iban.updated, IBAN issued V->>M: Read the IBAN back from the API [V7] - V->>SP: Client active, IBAN readable through the API [S4, V4, V12] - SP->>CL: Hand over IBAN, client starts sending EUR + V->>P: Client active, IBAN readable through the API [S4, V4, V12] + P->>CL: Hand over IBAN, client starts sending EUR ``` Notes on the flow: -- **SulPayments' app, shared credentials.** Monerium's reliance agreement is with - SulPayments, so the client profiles live in a white-label app in SulPayments' Monerium +- **The partner's app, shared credentials.** Monerium's reliance agreement is with + the partner, so the client profiles live in a white-label app in the partner's Monerium account. Only the app that onboarded a profile can read it or act on it, so Vortex uses the same app's client ID and secret. Monerium's guides describe one credential pair per app **[M2]**. Each partner gets its own white-label app, so a new partner means a new app and a new credential pair for Vortex **[V8]**. -- **Division of work.** SulPayments creates profiles and submits KYB. Vortex links +- **Division of work.** The partner creates profiles and submits KYB. Vortex links addresses, requests the IBAN, places refunds, and registers its own webhook - subscription. SulPayments must never link addresses, request or move IBANs, place + subscription. The partner must never link addresses, request or move IBANs, place orders, or change Vortex's webhook subscription. Closing a profile also closes its - IBAN, so SulPayments coordinates closures with Vortex **[S2]**. -- **KYB.** Companies must use Monerium's reliance route: SulPayments delivers company - details, form, verifications and files to Monerium directly. SulPayments calls + IBAN, so the partner coordinates closures with Vortex **[S2]**. +- **KYB.** Companies must use Monerium's reliance route: the partner delivers company + details, form, verifications and files to Monerium directly. The partner calls Monerium's KYB and profile endpoints itself; SatoshiPay does not proxy them (decided 2026-10-01). Approval takes seconds when the data follows Monerium's corporate KYB guide. Vortex never handles KYB data, which matches the security spec. Reading a profile returns only the company name, so KYB details stay - with SulPayments. + with the partner. - **Destination handover by profile ID (planned for the week of 2026-10-05).** Creating a profile returns its ID. - SulPayments then calls a new Vortex endpoint with that ID, the destination, its own + The partner then calls a new Vortex endpoint with that ID, the destination, its own client reference and a contact email **[V6]**. Vortex checks the profile exists in - SulPayments' app, stores the destination, and deploys the forwarder once the profile + the partner's app, stores the destination, and deploys the forwarder once the profile is approved. The destination is create-only, because it is fixed in the contract; a - change means a new account on SulPayments' written instruction. Vortex rejects zero, - token and contract addresses, and exchange addresses need SulPayments' confirmation - that they do not rotate. Until the endpoint is live, SulPayments sends the Monerium + change means a new account on the partner's written instruction. Vortex rejects zero, + token and contract addresses, and exchange addresses need the partner's confirmation + that they do not rotate. Until the endpoint is live, the partner sends the Monerium profile ID and the destination to Vortex directly, and Vortex sets the account up manually. - **Why the destination does not go through Monerium.** Monerium's profile API has no @@ -180,7 +180,7 @@ Notes on the flow: - **IBAN order.** Monerium issues an IBAN only for an address already linked to the profile, so the forwarder is linked first. A profile has one IBAN, which can be moved to another linked address. -- **Webhooks.** Vortex registers its own subscription on SulPayments' app; Monerium +- **Webhooks.** Vortex registers its own subscription on the partner's app; Monerium lists an app's subscriptions together. Monerium's guide says that list includes each subscription's secret, while the response schema has no secret field. Either way, Vortex reads the IBAN and the payer's IBAN back from Monerium's API instead of relying @@ -190,15 +190,15 @@ Notes on the flow: ### 4.3 What is built today - A Vortex operator deploys the forwarder, then one admin call maps the client with its - Monerium profile ID, SulPayments' client ID, the destination and the fee policy. + Monerium profile ID, the partner's client ID, the destination and the fee policy. - The keeper then links the forwarder and requests the IBAN automatically. The IBAN is recorded when Monerium confirms it. - The operator then activates the account. -- SulPayments can read the account and its IBAN through the Vortex API with its manager +- The partner can read the account and its IBAN through the Vortex API with its manager key. There is no dashboard view **[V3]**. - The backend uses one Monerium credential pair, shared with Vortex's retail EUR onramp. - Adopting the proposal changes four things. The B2B module gets its own credentials for - SulPayments' app **[V8]**. SulPayments supplies the destination by profile ID through + the partner's app **[V8]**. The partner supplies the destination by profile ID through the new endpoint, planned for the week of 2026-10-05 **[V6]**. Onboarding starts once the profile is approved and the destination is registered **[V1]**. The IBAN and the payer's IBAN are read back from Monerium's API **[V7]**. @@ -219,23 +219,23 @@ Notes on the flow: ### 4.5 Sandbox phase before production credentials -Monerium releases the production credentials for SulPayments' white-label app once it -sees test data in SulPayments' sandbox app: approved test client profiles onboarded -through SulPayments' KYB integration, IBANs issued, and test payments processed (agreed +Monerium releases the production credentials for the partner's white-label app once it +sees test data in the partner's sandbox app: approved test client profiles onboarded +through the partner's KYB integration, IBANs issued, and test payments processed (agreed on the call of 2026-09-30). Monerium's sandbox runs on Ethereum Sepolia. -SulPayments' steps **[S11]**: +The partner's steps **[S11]**: 1. Create a white-label app in its Monerium sandbox account at sandbox.monerium.dev, share the app's client ID and secret with Vortex, and onboard one or two test client profiles through its KYB integration. 2. Get a test API key from dashboard-sandbox.vortexfinance.co, for the API at - api-sandbox.vortexfinance.co, once Vortex has set SulPayments' profile up as the + api-sandbox.vortexfinance.co, once Vortex has set the partner's profile up as the manager of its clients. Register the webhook endpoint with that key through `POST /v1/webhook`, subscribing to `DEPOSIT_UPDATED` and `ACCOUNT_UPDATED`; the dashboard has no webhook screen. 3. For each test profile, send Vortex the Monerium profile ID and a Sepolia destination - wallet that SulPayments controls. + wallet that the partner controls. Vortex then sets up the forwarder, links it and the client's refund wallet, and requests the IBAN. In a joint session the parties run three test payments: a normal one, a large @@ -249,7 +249,7 @@ sequenceDiagram participant M as Monerium participant F as Forwarder participant V as Vortex keeper - participant SP as SulPayments + participant P as Partner B->>M: SEPA transfer to the client's IBAN M-->>V: order.created webhook, EUR arrived @@ -258,7 +258,7 @@ sequenceDiagram M-->>V: order.updated webhook, order processed V->>F: Watcher confirms the mint on chain V->>V: Deposit minted, 2-hour clock starts - V-->>SP: DEPOSIT_RECEIVED webhook + V-->>P: DEPOSIT_RECEIVED webhook ``` - Vortex listens on **two channels**. Monerium's webhooks carry the order details: @@ -353,7 +353,7 @@ flowchart TD - Once every chunk of a payment is converted, the keeper sends the whole USDC amount to the client's destination in **one transfer**. -- After the transfer is 32 blocks deep, SulPayments receives **DEPOSIT_CONVERTED**. It +- After the transfer is 32 blocks deep, the partner receives **DEPOSIT_CONVERTED**. It carries each chunk's reference rate, fee and subsidy, and the transaction hash of the final transfer. - **Without Vortex:** if the keeper stops for 24 hours, anyone can convert at the @@ -385,7 +385,7 @@ sequenceDiagram participant FL as Float wallet participant M as Monerium participant B as Payer's bank - participant SP as SulPayments + participant P as Partner Note over F: 2 hours passed, payment not fully converted V->>F: recover the payment's EURe and USDC @@ -395,7 +395,7 @@ sequenceDiagram R->>M: Redeem order to the payer's IBAN M->>B: SEPA payout from the client's IBAN M-->>V: order.updated, redemption processed - V-->>SP: DEPOSIT_RETURNED and DEPOSIT_UPDATED + V-->>P: DEPOSIT_RETURNED and DEPOSIT_UPDATED ``` - The payer gets back the **exact EUR amount**. Losses from the round trip and fees @@ -437,7 +437,7 @@ refund path builds on that, built on 2026-10-01: sends. - No Vortex company profile at Monerium is needed, and different clients' refunds never share a wallet. -- The client authorizes Vortex to send these refunds in the SulPayments terms. +- The client authorizes Vortex to send these refunds in the partner terms. Status: agreed with Monerium on 2026-09-30 for the pilot. Later, each client may instead name a fixed refund IBAN at onboarding, so every refund follows the same path **[V13]**. @@ -480,7 +480,7 @@ Monerium does not report a separate compliance-review state, so a payment under shows as pending. The `held` status in the API is therefore never set and will be removed **[V11]**. -### 9.2 What SulPayments receives +### 9.2 What the partner receives | Event | When | Key content | |---|---|---| @@ -496,24 +496,24 @@ removed **[V11]**. | Account, per client | IBAN, status, IDs, destination, forwarder address, fee policy | | Deposits, per client | Every deposit as its full snapshot, the same shape as `DEPOSIT_UPDATED` | -- The accounts call uses SulPayments' manager API key alone. The per-client calls add a +- The accounts call uses the partner's manager API key alone. The per-client calls add a header naming the client's Vortex profile ID, or use a key issued to the client. -- Webhooks are signed. SulPayments verifies each one against Vortex's published public +- Webhooks are signed. The partner verifies each one against Vortex's published public key and deduplicates on the event ID. - **Fallback:** the deposits call returns the current snapshot of every deposit, for polling if a webhook is missed. - **Reference IDs** in every snapshot: deposit, account, Vortex profile, Monerium - profile, Monerium order, SulPayments' client reference, and every transaction hash. + profile, Monerium order, the partner's client reference, and every transaction hash. - Amounts come as a EUR decimal and in base units: 18 decimals for EUR and EURe, 6 for USDC. -### 9.3 What SulPayments asked for +### 9.3 What the partner asked for -SulPayments' requirements of 2026-09-30, built on 2026-10-01: +The partner's requirements of 2026-09-30, built on 2026-10-01: - The API and webhooks expose the **full lifecycle**, from deposit through conversion to delivery, including IDs, amounts, timestamps, and hold or failure status. -- **API-first:** SulPayments' frontend fetches each sub-account's IBAN from the Vortex +- **API-first:** the partner's frontend fetches each sub-account's IBAN from the Vortex backend. How each stage is reported: @@ -532,7 +532,7 @@ How each stage is reported: | Account set up, IBAN issued, status changed | | `ACCOUNT_UPDATED`, and the accounts call | Not included yet: the incoming payment's SEPA reference and the payer's name. Add them -when SulPayments needs them. +when the partner needs them. ### 9.4 Exceptions and escalation @@ -541,7 +541,7 @@ when SulPayments needs them. - Operators can pause conversion, force a refund, or correct a deposit's status through admin endpoints. The runbook covers each case. - A joint Slack channel with Monerium is the agreed channel for payment questions. - Named owners and the escalation path between Vortex, SulPayments and Monerium are + Named owners and the escalation path between Vortex, the partner and Monerium are still to be agreed **[V5]**. ## 10. What Vortex can and cannot do @@ -590,19 +590,19 @@ when SulPayments needs them. - Refunds run through per-client refund wallets. A fixed refund IBAN per client may replace the dynamic payer IBAN later **[V13]**. -- SulPayments delivers KYB directly to its own white-label app and calls Monerium's KYB +- The partner delivers KYB directly to its own white-label app and calls Monerium's KYB endpoints itself; SatoshiPay does not proxy them. Vortex never handles KYB data. -- No SulPayments client has an existing Monerium profile. +- No partner client has an existing Monerium profile. - Monerium does not need to know or screen the client's final wallet. - Memo routing stays enabled, because clients are unlikely to use it. -- Testing runs in SulPayments' Monerium sandbox app on Sepolia before Monerium releases +- Testing runs in the partner's Monerium sandbox app on Sepolia before Monerium releases the production credentials (section 4.5). ### 12.2 Answered by Monerium (2026-09-30) | Topic | Answer | |---|---| -| Whose white-label app | A dedicated app in SulPayments' Monerium account, under SulPayments' reliance agreement. Vortex uses that app's client ID and secret. | +| Whose white-label app | A dedicated app in the partner's Monerium account, under the partner's reliance agreement. Vortex uses that app's client ID and secret. | | Onboarding steps | Confirmed: create profile, submit details, form and verifications, wait for `profile.updated` approved, link the forwarder and the refund wallet, request the IBAN. | | KYB route and speed | Corporates use the reliance endpoints. Approval takes seconds when the data follows Monerium's guidelines. | | Profile visibility | Only the credentials of the app that onboarded a profile can read it. | @@ -614,34 +614,34 @@ when SulPayments needs them. | Supporting document above €15,000 | The same agreement can be reused every time. | | Refund limits and fees | None. Some refunds are reviewed during business hours. | | Account fee | €10 per corporate account, per the agreement. | -| Partner apps | Each partner gets its own white-label app. SulPayments delivers KYB data and files directly; Vortex could proxy those calls later as tech provider. Decided 2026-10-01: no proxy, SulPayments calls the KYB endpoints itself. | -| Production credentials | Released after Monerium sees test data in SulPayments' sandbox app: approved test profiles onboarded through SulPayments' KYB integration, IBANs issued, test payments processed (section 4.5). | +| Partner apps | Each partner gets its own white-label app. The partner delivers KYB data and files directly; Vortex could proxy those calls later as tech provider. Decided 2026-10-01: no proxy, the partner calls the KYB endpoints itself. | +| Production credentials | Released after Monerium sees test data in the partner's sandbox app: approved test profiles onboarded through the partner's KYB integration, IBANs issued, test payments processed (section 4.5). | | Held and rejected payments | Monerium's monitoring holds payments for review during office hours, contacts the payer directly if it needs documents, and returns the funds if it cannot mint them. | | Third-party payers | Allowed. Monerium watches transaction patterns so accounts are not misused. | | Refund wallet approach | Agreed for the pilot. A fixed refund IBAN per client may replace it later. | | Communication | A joint Slack channel with Monerium is to be set up. | -| SulPayments' onboarding at Monerium | Documents in review on 2026-09-30, onboarding starting 2026-10-01. | +| The partner's onboarding at Monerium | Documents in review on 2026-09-30, onboarding starting 2026-10-01. | ### 12.3 Monerium | ID | Question | Why it matters | Status | Answer | |---|---|---|---|---| -| M2 | Can SulPayments' app have separate credentials for Vortex and SulPayments, or can linking addresses, requesting or moving IBANs, and managing webhooks be restricted to Vortex? If not, is there an audit log or notification for those actions? | Whoever holds the app credentials can redirect future mints | Partly answered 2026-09-30 | One app per partner. Separate credentials within one app not confirmed. | -| M3 | Is the €10 per corporate account billed to SulPayments or to Vortex, and is it one-off or recurring? | Commercial planning | Renegotiation ongoing | A discount for onboarding all SulPayments clients is being negotiated. | +| M2 | Can the partner's app have separate credentials for Vortex and the partner, or can linking addresses, requesting or moving IBANs, and managing webhooks be restricted to Vortex? If not, is there an audit log or notification for those actions? | Whoever holds the app credentials can redirect future mints | Partly answered 2026-09-30 | One app per partner. Separate credentials within one app not confirmed. | +| M3 | Is the €10 per corporate account billed to the partner or to Vortex, and is it one-off or recurring? | Commercial planning | Renegotiation ongoing | A discount for onboarding all partner clients is being negotiated. | | M4 | What triggers a review on a refund, and can refunds to the original payer be cleared in advance? | Refund timing promise | Open | | | M7 | Written confirmation of the items agreed verbally so far: the redemption-limitation disclosure, the issuer recovery backstop, SEPA recall and fraud loss allocation, per-IBAN suspension, and advance notice of changes to the link message. | Launch gate | Open | | -### 12.4 SulPayments +### 12.4 Partner | ID | Question or item to agree | Why it matters | Status | Answer | |---|---|---|---|---| | S1 | How many clients, and when? | Planning, and when the destination endpoint is needed | Open | | | S2 | Share the white-label app's production credentials with Vortex, and agree the usage rules in section 4.2: no address links, IBAN requests or moves, orders, or changes to Vortex's webhook subscription, and profile closures coordinated with Vortex. | Protects where client payments are minted | Production credentials follow the sandbox sign-off, section 4.5 | | -| S3 | Hand over each destination through the new Vortex endpoint by Monerium profile ID. Who at SulPayments approves a destination? | The destination is fixed in the contract | Proposal to confirm | | -| S4 | How does SulPayments get each client's IBAN? | API and dashboard scope | Answered 2026-09-30 | API-first: SulPayments' frontend fetches the IBAN from the Vortex API, section 9.3. | +| S3 | Hand over each destination through the new Vortex endpoint by Monerium profile ID. Who at the partner approves a destination? | The destination is fixed in the contract | Proposal to confirm | | +| S4 | How does the partner get each client's IBAN? | API and dashboard scope | Answered 2026-09-30 | API-first: the partner's frontend fetches the IBAN from the Vortex API, section 9.3. | | S5 | Do clients always pay from their own business bank accounts, or also from third parties? | Refund target. Monerium allows third-party payers | Open | | | S6 | Are destinations self-custody wallets or exchange deposit addresses? | Exchange addresses need an attestation that they do not rotate and accept contract transfers | Open | | -| S7 | Does the event model in section 9.3 cover the lifecycle requirement? Webhook endpoint and support contacts. | Status reporting | Built 2026-10-01, to confirm with SulPayments | SulPayments wants the full lifecycle with IDs, amounts, timestamps, and hold and failure status. | +| S7 | Does the event model in section 9.3 cover the lifecycle requirement? Webhook endpoint and support contacts. | Status reporting | Built 2026-10-01, to confirm with the partner | The partner wants the full lifecycle with IDs, amounts, timestamps, and hold and failure status. | | S8 | Is a two-hour window before a full refund right? Will clients authorize Vortex to refund from their IBAN? A Monerium review can delay a refund within business hours. | Refund terms in the agreement | Open | | | S9 | The agreement names a "Coinbase EURC oracle". The implementation uses the Coinbase Exchange EURC-USDC bid/ask midpoint. Is that what was meant? | Pricing terms | Open | | | S10 | Who bears Monerium's €10 per corporate account? | Commercial | Open | | @@ -653,10 +653,10 @@ when SulPayments needs them. |---|---|---|---| | V1 | Start onboarding once the profile is approved and the destination is registered, whichever comes last. | V6, V8 | Open | | V2 | Refunds through per-client refund wallets: derived from one seed, fixed in each forwarder as its recovery address, linked at onboarding. | None | Built 2026-10-01 | -| V3 | Dashboard view for SulPayments with clients, IBANs, deposits and refunds. Optional, since SulPayments integrates API-first. | S4 | Deprioritized | +| V3 | Dashboard view for the partner with clients, IBANs, deposits and refunds. Optional, since the partner integrates API-first. | S4 | Deprioritized | | V4 | Full lifecycle deposit events, section 9.3: snapshot event on every change, IDs, amounts, timestamps, hold and failure reasons, an account event, and the docs fix. | S7 | Built 2026-10-01 | -| V5 | Named owners per alert, and the escalation path between Vortex, SulPayments and Monerium, including the joint Slack channel with Monerium. | Meeting | Open | -| V6 | Endpoint for SulPayments to register a destination by Monerium profile ID: checks the profile exists, create-only, validated, no KYB data. | S3 | Planned to go live the week of 2026-10-05 | +| V5 | Named owners per alert, and the escalation path between Vortex, the partner and Monerium, including the joint Slack channel with Monerium. | Meeting | Open | +| V6 | Endpoint for the partner to register a destination by Monerium profile ID: checks the profile exists, create-only, validated, no KYB data. | S3 | Planned to go live the week of 2026-10-05 | | V7 | Read the IBAN and the payer's IBAN back from Monerium's API instead of trusting webhook payloads, and check in the sandbox whether listing subscriptions exposes their secrets. | None | Open | | V8 | Separate Monerium credentials for the B2B module, apart from the retail onramp, with one app and credential pair per partner. | S2 | Open | | V9 | Detect a mint to a refund wallet routed by payment memo, and handle it as a refund. | V2 | Open |