Skip to main content

Yuno Integration

Yuno is a payment orchestrator that allows Farfalla to offer multiple payment methods (cards, local wallets, bank transfers, etc.) through a single integration. In Farfalla it is integrated as one more gateway, behind the feature flag yuno_checkout_enabled.

This page is the integration index. Each subtopic has its own document with full details. For a comparative view with the other gateways (Stripe, MercadoPago, PayU), see Payments Overview — Yuno.

Summary

  • Integration type: Yuno JavaScript SDK (v1.5) embedded in-page + REST API calls from the backend.
  • Feature flag: yuno_checkout_enabled.
  • SDK loader: resources/views/modules/yuno-sdk-library.blade.php.
  • Main service: App\Domains\Commerce\Gateways\Yuno\YunoService (implements GatewayInterface).
  • Supports: one-off payments, recurring subscriptions, card enrollment without charge (trial), full and partial refunds.
  • Key differentiator: the SDK returns a One-Time Token (OTT) that the backend sends to the Yuno API; card data never passes through Farfalla (reduced PCI scope).

Code Structure

app/Domains/Commerce/
├── Gateways/Yuno/
│ ├── YunoBaseService.php # Shared logic: build payload, log masking, webhook helpers
│ ├── YunoCustomerService.php # Create/retrieve customer in Yuno
│ ├── YunoOneOffPaymentService.php # One-off flow: create payment, handle refund
│ ├── YunoRecurringPaymentService.php # Recurring flow: subscription, enrollment, partial refund
│ ├── YunoService.php # Orchestrator implementing GatewayInterface
│ ├── YunoPaymentStatus.php # Yuno status enum
│ └── Events/
│ ├── Payment.php # Events fired by payment webhooks
│ └── Subscription.php # Events fired by subscription webhooks
└── Support/Yuno/
├── YunoCheckoutSession.php # checkout_session token (one-off)
├── YunoConnector.php # HTTP client, endpoints, masking
├── YunoCurrencyConversion.php # Currency conversion via Yuno API (COM-142)
├── YunoCustomer.php # Customer entity
├── YunoCustomerSession.php # customer_session token (enrollment)
├── YunoEntity.php # Base entity
├── YunoPayment.php # Payment entity
├── YunoPaymentMethodsToEnroll.php # Enrollable payment methods
├── YunoRefund.php # Refund entity
└── YunoSubscription.php # Subscription entity

Frontend:

resources/
├── views/
│ ├── modules/yuno-sdk-library.blade.php # SDK loader (CDN, v1.5)
│ └── livewire/
│ ├── checkout-v2/yuno-payment-form.blade.php # Payment form in checkout
│ └── my-account/change-yuno-payment-method.blade.php # Payment method change modal
└── js/
├── yuno-libraries.js # Helpers for subscriptions and enrollment
└── alpine/alpine-components/yuno-checkout-v2-component.js # Alpine store for one-off checkout

Subtopics

One-off payment flow

See Yuno OTT (One-Time Token) and Yuno Frontend / SDK. The user clicks the Yuno button → the SDK mounts in-page with mountCheckout() → the SDK generates an OTT when the card is confirmed → Livewire sends the OTT to the backend → YunoService::buildPaymentPayloadForOTT() builds the payload → POST /v1/payments to Yuno → if 3DS is required, the SDK handles it in-page → the final response approves or rejects the UserPlan.

Recurring payment flow

See Yuno Subscriptions and Trial. Yuno has a native Subscriptions API: recurring charges are triggered by Yuno autonomously, without any Farfalla jobs. The first cycle is charged as a one-off payment; the Yuno API returns a vaulted_token in the response, and Farfalla uses that token to create the subscription. Subsequent charges are dispatched directly by Yuno using that token. See also OTT vs vaulted token.

Enrollment without charge (trial)

See Yuno Subscriptions and Trial. Yuno supports mountEnrollmentLite() to store a card without generating a charge. This is used for trial flows where the user must register a payment method but is not billed until the first cycle. The subscription is created with initial_payment_validation: true and availability.start_at = now + trial_days, telling Yuno when to trigger the first real charge.

Currency conversion (cross-border)

See Yuno OTT — Currency conversion. For cross-border currencies (CLP, MXN, etc.), Farfalla first calls POST /v1/currency-conversion, passing the OTT as payment_method.token so that Yuno queries the BIN against the provider (MercadoPago) and returns the actual rate. The Yuno API is the source of truth — conversion is not calculated locally. Implementation lives in YunoCurrencyConversion.php. See ticket COM-142 for context.

Webhooks / IPNs

See Yuno IPN / Webhooks. Yuno sends payment.* and subscription.* webhooks to a shared IPN URL (with the {gateway_type} = yuno parameter as a discriminator). Multi-tenancy is resolved by extracting tenant_id from Yuno metadata (an array of {key, value} objects). Idempotency is based on gateway_event_id plus a lookup in ipn_records.

Status mapping

See Yuno IPN — Status mapping. Complete table of the 18 YunoPaymentStatus values mapped to publica.la statuses (approved, pending, cancelled, refunded, error).

Refunds and transactions

See Yuno Refunds and Transactions. Supports full refund (one-off and recurring) and partial refund (recurring only). When Yuno responds with PENDING_PROVIDER_CONFIRMATION, the system saves a PendingPaymentRefund and the VerifyPendingRefunds job polls every 5 minutes until confirmed (maximum 12 attempts, approximately 1 hour).

Traceability and debugging

All Yuno integration traces are stored in activity_log under two channels:

  • yuno_api — interactions with the Yuno API from the backend. The HTTP connector logs every request and response (with secrets and sensitive data masked). The services (YunoBaseService, YunoService, YunoOneOffPaymentService, YunoCustomerService, YunoEntity) record operation results, handled errors, and warnings (for example, currency conversion with fallback, payment not found when attempting a refund).
  • yuno_webhooks — IPN reception and deduplication. Covers payloads without an event ID, duplicate webhooks, and cases where the order associated with the event cannot be found.

Actions applied by an IPN to payments and orders are recorded in payment_event, a channel shared across all gateways. See Payments Overview — Debugging for the general traceability guide.

Response structure: payments and transactions

In the Yuno API, a payment is the root object and contains an array of transactions representing specific operations: the initial charge is a transaction of type PURCHASE; each refund is a transaction of type REFUND. Yuno also exposes AUTHORIZE, CAPTURE, and CHARGEBACK in its model, but Farfalla today only works with PURCHASE and REFUND.

There is an inconsistency in the shape of the field: responses from the refund endpoint and webhooks return transactions as a single object, while the payment GET endpoint returns it as an array. Farfalla normalizes the field to an array at all entry points, detecting whether the received value has a direct id property (object) or not (array). That normalization function is reused in the refund service, the payment entity, the verification job, and the webhook handler.

References

X

Graph View