Feature Specification: UnivaPay Card Payment Integration (MVP)

Feature Branch: 002-univapay-card-payment

Created: 2026-08-02

Status: Draft

Input: User description: “UnivaPay MVP: add an application entry point on the payment settings screen; manual registration of integration credentials (Store ID / App Token / Secret / Webhook info); connection states (Not Connected / Connected / Unavailable); selectable ‘Card Payment (UnivaPay)’ in sales settings (disabled when not connected); customer-facing label is only ‘Credit Card’; inline form inside the application screen; link the Yoyacoo application ID via metadata; reflect success/failure/cancel via Webhook; installment payments ON/OFF only; refunds/cancellations by customer and supplier (status change + email, same as Stripe); verify on staging with test tokens”

Overview

Add UnivaPay as a credit card payment provider alongside the existing Stripe integration.
The MVP covers credit card payments only. Other payment methods (PayPay, bank transfer, convenience store), automated onboarding (automatic store creation), and automated platform-fee splitting are out of scope.
Suppliers (users) contract with UnivaPay directly and manually register the issued credentials on the payment settings screen. Customers never see the payment provider’s name — only “Credit Card” is displayed.

User Scenarios & Testing (mandatory)

User Story 1 - UnivaPay Connection Setup (Priority: P1)

A supplier opens the payment settings screen, sees guidance on how to apply for UnivaPay (application entry point), and enters the integration credentials issued in the UnivaPay merchant console (Store ID, store-type App Token, Secret). After saving, the connection status (Not Connected / Connected / Unavailable) is displayed based on a verification check. The screen also guides the supplier through the two required UnivaPay console configurations: (a) registering the Yoyacoo customer-site domain on the app token (mandatory for the inline form to load), and (b) registering the webhook — for which the screen displays the receiver URL and the Authorization value to set.

Why this priority: Without the connection setup, every downstream feature (sales settings, payment, refunds) cannot work — it is the foundation.

Independent Test: Can be fully tested by entering and saving credentials on the payment settings screen and verifying the status transitions. Delivers standalone value (onboarding preparation) even before payment features are implemented.

Acceptance Scenarios:

  1. Given a supplier not connected to UnivaPay, When they open the payment settings screen, Then the UnivaPay application guidance and the credential input form are displayed, with status “Not Connected”
  2. Given an unconnected supplier, When they enter a valid Store ID, store-type App Token, and Secret and save, Then the credentials are verified against UnivaPay and the status becomes “Connected”
  3. Given an unconnected supplier, When they enter invalid credentials and save, Then the status becomes “Unavailable” and guidance prompting re-entry is displayed
  4. Given a connected supplier, When they open the payment settings screen, Then the webhook receiver URL and the Authorization value to register in the UnivaPay console are displayed
  5. Given a supplier registering credentials, When they follow the on-screen guidance, Then it instructs them to register the Yoyacoo customer-site domain on the UnivaPay app token (required for the inline form to load)

User Story 2 - Selecting “Card Payment (UnivaPay)” in Sales Settings (Priority: P1)

A connected supplier can select “Card Payment (UnivaPay)” as a payment method in a service’s sales settings. If UnivaPay is not connected or is unavailable, the option cannot be selected and guidance prompting connection is displayed.

Why this priority: It is the entry point for accepting payments; together with US1 it completes the seller-side setup.

Independent Test: Can be tested by opening the sales settings screen in both connected and unconnected states and verifying selectability and saved results.

Acceptance Scenarios:

  1. Given a supplier connected to UnivaPay, When they select “Card Payment (UnivaPay)” in a service’s sales settings and save, Then UnivaPay card payment becomes enabled for that service
  2. Given a supplier not connected to UnivaPay, When they open the sales settings screen, Then “Card Payment (UnivaPay)” is not selectable and guidance prompting connection in the payment settings is displayed
  3. Given a service with UnivaPay enabled, When a customer views the payment methods on the application screen, Then no provider name (e.g., “Stripe”, “UnivaPay”) is shown — only “Credit Card”

User Story 3 - Customer Card Payment and Status Reflection (Priority: P1)

When a customer selects “Credit Card” on the application screen, the UnivaPay inline form (card input form) is displayed within the page. The customer enters card details and executes the payment, and UnivaPay processes the charge. The result is delivered to Yoyacoo via webhook. The Yoyacoo application ID is attached as UnivaPay metadata, so when the webhook is received the application is identified from the metadata and the payment result (success / failure / cancel) is reflected in the application status. On success, the same post-payment processing as Stripe (confirmation email, etc.) is executed.

Why this priority: This is the core customer experience of the feature — without it the integration has no meaning.

Independent Test: Using test tokens, complete application → inline-form payment → webhook receipt → verify the application status becomes “payment completed”. Failure cases are reproducible with test cards.

Acceptance Scenarios:

  1. Given a service with UnivaPay card payment enabled, When a customer selects “Credit Card” on the application screen, Then a card input form (inline form) is displayed within the application screen
  2. Given valid card details entered in the inline form, When the customer executes the payment, Then the Yoyacoo application ID is attached to the UnivaPay payment as metadata, and after webhook receipt the application status is updated to payment successful and a confirmation email is sent
  3. Given a payment failure (insufficient funds, invalid card, etc.), When the failure is notified via webhook, Then the application status is updated to payment failed and the customer can retry
  4. Given a webhook whose metadata application ID matches no application, When the webhook is received, Then it is recorded as an error and no duplicate or incorrect status reflection occurs

User Story 4 - Refunds and Cancellations (Priority: P2)

For paid applications, both the customer and the supplier can perform refunds/cancellations through the same flows as Stripe payments. The result is executed as a UnivaPay refund/cancel, and — same as Stripe — the application status is changed and notification emails are sent.

Why this priority: Essential for post-payment operations, but payment acceptance (P1) comes first.

Independent Test: Create a paid application in the test environment, execute refund/cancel from both the customer side and the supplier side, and verify status changes and email delivery.

Acceptance Scenarios:

  1. Given an application paid successfully via UnivaPay, When the supplier performs a cancellation (refund), Then the refund/cancel is executed on the UnivaPay side, the application status is updated, and the same notification emails as Stripe are sent
  2. Given an application paid successfully via UnivaPay, When the customer cancels under cancellable conditions, Then the same refund processing, status change, and email delivery as a Stripe payment occur
  3. Given the refund processing fails on the UnivaPay side, When the result returns, Then the application status remains consistent and the operator is notified of the failure

User Story 5 - Installment Payments ON/OFF (Priority: P3)

The supplier configures only an ON/OFF toggle for installment payments in the sales settings. The installment count is selected by the customer inside the UnivaPay inline form, so Yoyacoo does not manage installment counts.

Why this priority: An add-on feature — payments work with one-time payment only, hence P3.

Independent Test: Open the application screen for a service with installments ON and verify the installment count selector appears in the inline form; verify it does not appear when OFF.

Acceptance Scenarios:

  1. Given a service with installments ON, When the customer displays the inline form, Then they can select an installment count within the form
  2. Given a service with installments OFF, When the customer displays the inline form, Then no installment selector is shown and only one-time payment is available

Edge Cases

  • Webhook not delivered or delayed: the application remains in “payment processing” and both customer and supplier can see the state (active status confirmation via the Charge GET API is an acceptable future enhancement, but the MVP is webhook-centric). Note: UnivaPay officially recommends not relying solely on webhooks for payment determination — a manual “check status” action for stuck applications is a candidate enhancement
  • Duplicate webhook delivery for the same application: processing must be idempotent — no duplicate status changes or duplicate emails (UnivaPay explicitly retries and may deliver the same event more than once)
  • Webhook receiver responsiveness: UnivaPay treats any response slower than 3 seconds as a failure and retries — the receiver MUST acknowledge within 3 seconds and process the event asynchronously afterwards
  • A connected supplier changes or revokes credentials: status transitions to “Unavailable” and new payments for the affected services are no longer accepted
  • Customer closes the page mid-payment: the final state converges correctly via webhook status reflection
  • Mixing production and test tokens: tokens are separated per environment (staging uses test tokens only)

Requirements (mandatory)

Functional Requirements

Connection Setup

  • FR-001: The payment settings screen MUST display an entry point (explanation/link) guiding the supplier to apply for UnivaPay, noting that the merchant account is applied for directly with UnivaPay (no self-service signup) and linking to UnivaPay’s application channels
  • FR-002: Suppliers MUST be able to enter and save Store ID, store-type App Token, and Secret. The Secret MUST be stored securely and MUST NOT be re-displayed in plaintext on screen (UnivaPay shows the Secret only once at token creation)
  • FR-003: The system MUST verify the saved credentials against UnivaPay and manage/display the connection status with three values: “Not Connected”, “Connected”, “Unavailable”
  • FR-004: The payment settings screen MUST display the information required for webhook configuration on the UnivaPay console: the receiver URL, the Authorization value to set on the webhook, and the event types to subscribe to (charge finished, refund finished, cancel finished)
  • FR-005: The payment settings screen MUST guide the supplier to register the Yoyacoo customer-site domain on the UnivaPay app token, since UnivaPay authenticates inline form requests by registered domain

Sales Settings

  • FR-006: A service’s sales settings MUST allow selecting “Card Payment (UnivaPay)” as a payment method
  • FR-007: When the UnivaPay connection status is not “Connected”, “Card Payment (UnivaPay)” MUST NOT be selectable, and guidance prompting connection MUST be displayed
  • FR-008: Customer-facing payment method displays MUST NOT show provider names (Stripe / UnivaPay) — only “Credit Card”

Payment

  • FR-009: The UnivaPay inline form MUST be displayed within the application screen so the customer can enter card details without page navigation
  • FR-010: When executing a payment, the Yoyacoo application ID MUST be attached to the UnivaPay payment as metadata to link them
  • FR-011: Payment results (success / failure / cancel) MUST be received via webhook and reflected in the application status based on the metadata application ID. Webhook processing MUST be idempotent
  • FR-012: On payment success, the same application confirmation processing as Stripe (confirmation email, etc.) MUST be executed

Refunds and Cancellations

  • FR-013: Suppliers and customers MUST be able to execute refunds/cancellations through the same flows as Stripe payments
  • FR-014: Refund/cancellation results MUST be reflected with application status changes and email notifications, same as Stripe

Installments

  • FR-015: Installment payments MUST be configurable as ON/OFF only in sales settings; the installment count is selected by the customer inside the UnivaPay inline form (Yoyacoo does not manage counts)

Environments

  • FR-016: On the staging environment, the full flow (payment, webhook, refund) MUST be verifiable using UnivaPay test tokens (production and test tokens MUST be separated per environment)

Key Entities

  • UnivaPay Connection: Per-supplier UnivaPay configuration. Holds Store ID, App Token, Secret (secured), and connection status (Not Connected / Connected / Unavailable)
  • Application (Reservation/Order): Existing application entity, extended with a reference to the UnivaPay charge ID and payment state, used for webhook matching and status reflection
  • Payment Method Settings (per service): Per-service enablement of “Card Payment (UnivaPay)” and the installment ON/OFF flag

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001: A supplier can complete UnivaPay credential registration within 5 minutes, and the resulting connection status is reflected on screen immediately
  • SC-002: A customer can go from selecting “Credit Card” on the application screen to completing payment within 3 minutes, without page navigation
  • SC-003: 100% of payment successes and failures are reflected in application status via webhook; duplicate webhook deliveries cause no duplicate status changes or duplicate emails
  • SC-004: Refund/cancellation success rate (normal completion on the UnivaPay side) is equivalent to Stripe payments, and failures are always notified to the operator
  • SC-005: All scenarios — payment success, payment failure, refund — can be reproduced and verified on staging using test tokens
  • SC-006: Neither “Stripe” nor “UnivaPay” provider names appear on any customer-facing screen or email

Assumptions

  • Contract model: Multi-tenant — each supplier contracts with UnivaPay individually and registers their own Store ID and tokens (automatic store creation/onboarding by Yoyacoo is out of MVP scope). Per UnivaPay docs, the app token itself identifies the store, so Store ID may be auto-retrievable from the token — whether to keep it as a manual input is a plan-phase simplification decision
  • Merchant account application: UnivaPay merchant accounts are not self-service — the supplier applies on UnivaPay’s website (導入のご相談 / デモアカウント申請), UnivaPay sends an application form and performs human screening before issuing the account. UnivaPay’s ips-support@univapay.com mailbox is existing-merchant support only and is not the application channel
  • Test account availability: UnivaPay issues an instant demo/test account usable before/during screening, so staging verification (FR-016) is not blocked while the production account is under review
  • Domain registration: The inline form only loads from domains registered on the UnivaPay app token; the supplier must register the Yoyacoo customer-site domain in the UnivaPay console as part of setup (staging/production domains each need registration)
  • Secret necessity: The Secret is not needed for the inline form itself, but IS required for the backend API calls in scope (refunds, cancels, charge status checks), so collecting it is justified
  • Fees: Automated platform-fee splitting on UnivaPay payments is out of MVP scope. Fee handling follows the existing operational/billing flow unchanged
  • Charge type: Authorization and capture happen together (immediate capture), matching the existing Stripe payment behavior. Deferred/scheduled capture is out of scope
  • Payment methods: Credit card only (the UnivaPay inline form is card-only). PayPay, bank transfer, convenience store payments, etc. are future phases
  • Refund/cancel permissions: “Customers and users can do it” is interpreted as applying the same permissions and flows as the existing Stripe payment (customer cancel / supplier cancellation) to UnivaPay payments — no new permissions are introduced
  • Active status polling: Actively confirming payment state via the Charge GET API is not required for the MVP; operation is webhook-centric (per UnivaPay’s answer)
  • 3-D Secure: Follows UnivaPay’s default 3-D Secure execution rules; no custom control on the Yoyacoo side
  • Impact on existing Stripe: Stripe card payments remain available; which card processor to use is selected per service in the sales settings