Architecture Overview: UnivaPay Integration in Yoyacoo
Architecture Overview: UnivaPay Integration in Yoyacoo
How the UnivaPay provider structure, the Yoyacoo feature structure, and the supplier
connection/storage flows fit together. Companion to spec.md and research.md.
1. UnivaPay structure (provider side)
UnivaPay Merchant (加盟店) ← supplier's contract with UnivaPay
└── Store (店舗) ← where payments happen (1 merchant = 1 store in practice)
├── App Token (店舗トークン) ← identifies which store processes payments
│ ├── Token (JWT) ← browser-side auth (inline form)
│ ├── Secret ← shown ONCE at creation; backend API auth (Bearer {secret}.{jwt})
│ └── Registered domains ← inline form ONLY loads from these domains
└── Webhooks ← POST events: charge_finished / refund_finished / cancel_finished
└── auth_token ← merchant-defined value sent as Authorization header (per-store)
Key facts (see research.md for sources):
- The app token IS the store identifier → Store ID may be auto-retrieved from the token
- Store-type tokens only (merchant-type tokens have no practical value)
- Test mode = separate test-mode app token; payloads carry
mode: test|live
2. Yoyacoo feature structure
The feature mirrors the existing Stripe architecture 1:1, with one structural difference
(webhook verification is per-store, not a global env secret).
| Layer | Stripe today (existing) | UnivaPay (new) |
|---|---|---|
| Common package — API wrapper | common/src/Base/Traits/StripeConnectPayment.php |
UnivapayPlatform trait: verifyCredentials, createCharge, refundCharge, cancelCharge |
| Common package — model | UserPaymentSetting (stripe_connect_id) |
UserPaymentUnivapay model (new table) |
| Supplier app (user) — settings UI/API | user/app/Domains/Account/... payment settings |
Payment settings screen: entry point, credential form, status display, webhook guidance |
| Sales settings | ServicePaymentMethod |
add univapay payment type + installment ON/OFF |
| Customer app — checkout | customer/.../PaymentSelection + Stripe JS |
inline form embed (registered domain) + “Credit Card” label |
| Webhook receiver | admin host only: /stripe/webhook etc. + env secrets |
shared admin-host endpoint /univapay/webhook, verified per-store auth_token |
| Order reference | orders.stripe_* columns |
orders.univapay_charge_id |
| Side effects | Order status + emails | Same flow (Stripe parity) |
3. How a supplier connects (MVP: manual registration, no OAuth)
Unlike Stripe Connect (Yoyacoo creates connected accounts via OAuth), the supplier is their own
UnivaPay merchant and enters credentials manually:
- Apply for a UnivaPay merchant account (via UnivaPay’s website, outside Yoyacoo) — there is
no self-service signup. The supplier contacts UnivaPay (導入のご相談: univapay.com/contact/,
or デモアカウント申請 for an instant test account: univapay.com/form-demo/), UnivaPay sends an
application form, in-house staff perform human screening (審査), and the production merchant
account is issued. A test account usable for staging is issued immediately, before screening
completes.ips-support@univapay.comis existing-merchant support only — do not list it as the
signup channel. Seeresearch.md§8. - Supplier gets console access (
merchant.univapay.com) - Console: create a store app token (Token + Secret — copy the Secret immediately), register
the Yoyacoo customer-site domain (mandatory for the inline form) - Yoyacoo payment settings: enter Store ID, App Token, Secret
- Yoyacoo verifies via authenticated API call → status Connected / Unavailable / Not Connected
- Yoyacoo displays webhook receiver URL + generated auth_token; supplier registers the
webhook in the UnivaPay console with triggers: charge, refund, cancel - Repeat with a test-mode token for staging (FR-015)
4. Where UnivaPay information is stored
| Data | Location | Notes |
|---|---|---|
| Per-supplier connection | user_payment_univapays |
store_id, api_key, secret (encrypted), webhook_auth_token, charges_enabled, status, mode |
| Transaction reference | orders.univapay_charge_id |
charge UUID for webhook matching + refund/cancel calls |
| Per-service enablement | ServicePaymentMethod (+ installment flag) |
FR-005/FR-006/FR-014 |
| Webhook replay guard | idempotency record keyed by event id |
duplicates are guaranteed possible |
| Shared config (not per-supplier) | .env / config/services.php |
API base URL, test/live mode switch, log channels |
Detailed schema: data-model.md.
5. Where the supplier gets each credential
| Field | Source |
|---|---|
| Merchant account | Apply on univapay.com — 導入のご相談 (univapay.com/contact/) → 申込フォーム → screening (審査) → account issued (not self-service) |
| Instant test account | univapay.com/form-demo/ (issued immediately, usable before/during screening) |
| Store ID | UnivaPay console → store settings (or auto-retrieved from token — simplification candidate) |
| App Token (JWT) | Console → アプリトークン → 新規作成 (select 店舗) |
| Secret | Same screen — shown only once; lost = rotate token |
| Domain registration | Same token screen — Yoyacoo customer-site domain (staging + production separately) |
| Webhook URL + auth_token | Generated/displayed by Yoyacoo (payment settings screen, FR-004) |
| Test credentials | Console → test-mode app token; test card numbers under テスト課金 (or the instant demo account above) |
6. Key differences vs Stripe to keep in mind
- No OAuth onboarding — manual credential entry; Yoyacoo cannot create stores on the
supplier’s behalf in the MVP - Webhook auth is per-supplier (
auth_tokenstored per connection), not a single
STRIPE_WEBHOOK_SECRET-style env value — verification looks up the connection bystore_id - Domain registration gates the inline form — if missing, payment silently fails to load
- 3-second 200 rule — acknowledge webhooks fast, process asynchronously (queue)
- Webhooks are best-effort — UnivaPay recommends API confirmation as the reliable path; MVP
stays webhook-centric with a manual “check status” enhancement candidate