spree-payments

Integrate payment gateways with Spree — PaymentMethod model, the v5.4+ PaymentSession provider-agnostic checkout flow, Stripe via `spree_stripe` (Apple/Google Pay, Link, Connect for marketplaces), Adyen via `spree_adyen`, PayPal via `spree_paypal_checkout`, StoreCredit / GiftCard as payment methods, refunds, payment state machine, and authoring a custom gateway. Use when wiring a payment integration, handling webhooks from a gateway, or debugging payment-state issues.

17 stars

Best use case

spree-payments is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Integrate payment gateways with Spree — PaymentMethod model, the v5.4+ PaymentSession provider-agnostic checkout flow, Stripe via `spree_stripe` (Apple/Google Pay, Link, Connect for marketplaces), Adyen via `spree_adyen`, PayPal via `spree_paypal_checkout`, StoreCredit / GiftCard as payment methods, refunds, payment state machine, and authoring a custom gateway. Use when wiring a payment integration, handling webhooks from a gateway, or debugging payment-state issues.

Teams using spree-payments should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/spree-payments/SKILL.md --create-dirs "https://raw.githubusercontent.com/OrcaQubits/agentic-commerce-skills-plugins/main/dist/antigravity/spree-commerce/.agent/skills/spree-payments/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/spree-payments/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How spree-payments Compares

Feature / Agentspree-paymentsStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Integrate payment gateways with Spree — PaymentMethod model, the v5.4+ PaymentSession provider-agnostic checkout flow, Stripe via `spree_stripe` (Apple/Google Pay, Link, Connect for marketplaces), Adyen via `spree_adyen`, PayPal via `spree_paypal_checkout`, StoreCredit / GiftCard as payment methods, refunds, payment state machine, and authoring a custom gateway. Use when wiring a payment integration, handling webhooks from a gateway, or debugging payment-state issues.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Spree Payments

## Before writing code

**Fetch live docs**:
1. Fetch https://spreecommerce.org/docs/developer/core-concepts/payments for the Payment + PaymentSession model.
2. Fetch the integration repo README — https://github.com/spree/spree_stripe / spree_adyen / spree_paypal_checkout — for current install + config.
3. Check the gateway's own SDK docs (Stripe / Adyen / PayPal) for the latest API version.
4. Inspect the live `Spree::Payment` source for state transitions and column names.
5. Check the v5.4 announcement for the PaymentSession introduction.

## Conceptual Architecture

### PaymentMethod, Payment, PaymentSession

| Model | Purpose |
|-------|---------|
| **`PaymentMethod`** | Admin-configured way to pay (Stripe, Adyen, PayPal, StoreCredit, etc.). Per-store, per-currency. |
| **`Payment`** | A specific payment attempt on an Order. Has a `state`, a `source` (CreditCard/StoreCredit/...), and an `amount`. |
| **`PaymentSession`** (v5.4+) | Provider-agnostic envelope around a payment authorization. Wraps Stripe Payment Intents, Adyen sessions, PayPal orders. |

### Payment State Machine

```
checkout → processing → pending → completed
                    ↓
                  failed | void | invalid
```

- **`checkout`** — initialized, waiting for capture
- **`processing`** — sent to gateway
- **`pending`** — gateway accepted, awaiting async confirmation (3DS, ACH)
- **`completed`** — captured
- **`failed`** — declined
- **`void`** — voided pre-capture
- **`invalid`** — gateway returned an unparseable response

### Payment Sources

Most `Payment` rows have a polymorphic `source`:
- `Spree::CreditCard` — tokenized card data
- `Spree::StoreCredit` — user's store credit balance
- `Spree::GiftCard` — gift card balance
- Gateway-specific (`Spree::PayPalCheckout::Order`, etc.)

### The v5.4 PaymentSession Flow

1. Storefront calls `POST /api/v3/store/checkout/payment_sessions` with `payment_method_id`.
2. Spree creates a `PaymentSession`, hits the gateway's session API (Stripe Payment Intent, Adyen `/sessions`, PayPal `/v2/orders`).
3. Storefront renders the gateway's hosted UI (Stripe Elements, Adyen Drop-in, PayPal Buttons) with the returned client secret / session data.
4. User authorizes (handles 3DS, SCA, Apple/Google Pay).
5. Storefront calls `POST /api/v3/store/checkout/complete`.
6. Spree captures the session into a `Payment` and advances the order.

Provider differences are hidden behind the `PaymentSession` envelope — the storefront code is gateway-agnostic above the UI layer.

### Stripe via spree_stripe

- One-click installer in admin (Settings → Payment Methods → Stripe → Connect)
- Supports cards, Apple Pay, Google Pay, Link, Klarna, Affirm, SEPA
- **Stripe Connect** for marketplace payouts (Enterprise marketplace)
- Webhooks: `payment_intent.succeeded`, `payment_intent.payment_failed`, etc. routed to `/webhooks/stripe`

### Adyen via spree_adyen

- Supports cards + many local payment methods
- Drop-in UI in the Next.js storefront
- HMAC-signed webhooks

### PayPal via spree_paypal_checkout

- PayPal Checkout (Smart Buttons) + PayPal Credit
- Server-side order creation

### Refunds

Refund a captured Payment:

```ruby
refund = Spree::Refund.create!(
  payment: payment,
  amount: payment.amount,
  reason: Spree::RefundReason.first
)
refund.perform!
```

`perform!` hits the gateway's refund endpoint and updates the `Payment#state` if fully refunded.

### Reimbursement vs Refund

- **Refund** — credits back the original payment method.
- **Reimbursement** — orchestrates the return flow; can issue a Refund OR a StoreCredit, on a CustomerReturn.

### StoreCredit and GiftCard as Payment Methods

Both work as native payment sources. The checkout state machine skips the `payment` step if store credit fully covers the order.

## Implementation Guidance

### Adding Stripe to a Spree v5.4+ Project

```ruby
# Gemfile
gem 'spree_stripe'

# Then
bundle install
bin/rails g spree_stripe:install
bin/rails db:migrate
```

In admin → Settings → Payment Methods → Stripe → connect via OAuth (Stripe Express / Standard). Set webhook endpoint in Stripe dashboard to `https://yourdomain/webhooks/stripe`. Verify the env vars (`STRIPE_API_KEY`, `STRIPE_PUBLISHABLE_KEY`, `STRIPE_WEBHOOK_SECRET`) — check the README for the current naming.

### Creating a PaymentSession (v5.4+ headless)

```typescript
// In a Server Action of the Next.js storefront
const session = await spree.checkout.createPaymentSession({
  paymentMethodId: 'pm_stripe',
});
// session.clientSecret used by Stripe Elements
// session.dropInPayload used by Adyen Drop-in
```

(Verify against `@spree/sdk` docs.)

### Authoring a Custom Gateway

```ruby
# app/models/my_app/payment_method/custom_gateway.rb
class MyApp::PaymentMethod::CustomGateway < Spree::PaymentMethod
  def payment_source_class
    Spree::CreditCard
  end

  def gateway_class
    MyApp::Gateways::CustomBilling
  end

  def supports?(source)
    source.is_a?(Spree::CreditCard)
  end

  def actions
    %w[capture void credit]
  end
end

# app/models/my_app/gateways/custom_billing.rb
class MyApp::Gateways::CustomBilling
  def initialize(options = {})
    @api_key = options[:api_key]
  end

  def authorize(amount_cents, source, options = {})
    # Hit the gateway's authorize endpoint
    # Return ActiveMerchant::Billing::Response.new(...)
  end

  def capture(amount_cents, authorization_token, options = {})
    # …
  end

  def void(authorization_token, options = {})
    # …
  end

  def credit(amount_cents, authorization_token, options = {})
    # refund
  end
end
```

Register the payment method type in an initializer:

```ruby
Rails.application.config.spree.payment_methods << MyApp::PaymentMethod::CustomGateway
```

### Webhook Handling

Spree gateway gems mount their own webhook routes (e.g., `/webhooks/stripe`). When customizing:

```ruby
# Subscribe to Spree's own events after webhook processing
class PaymentSubscriber < Spree::Subscriber
  subscribes_to 'payment.paid'
  on 'payment.paid', :sync_to_accounting
end
```

### Handling 3DS / SCA

`Payment#state == 'pending'` after authorize means the gateway is waiting for the customer to complete a challenge. The storefront polls or listens for the gateway's webhook, then either `payment.complete!` or `payment.failure!`.

### Split Tender (StoreCredit + Card)

Spree natively supports multiple `Payment` rows per order. The order updater allocates outstanding balance across them in order of creation. The order state machine completes only when sum(payments.completed) == order.total.

### Common Pitfalls

- **Hardcoding gateway secrets in `config/spree.rb`** — use Rails credentials or env vars.
- **Manually setting `Payment#state = 'completed'`** — bypasses the gateway flow; reconciliation breaks.
- **Refunding more than the original Payment amount** — gateway rejects; pre-validate.
- **Forgetting webhook signature verification** — gateway gems handle this, but custom integrations must verify HMAC.
- **PaymentSession not cleaned up on cart abandonment** — gateways have their own expiry; don't rely on Spree to release holds.
- **Test vs live keys confusion** — Stripe `pk_test_` and `sk_test_` must match; mixing modes silently fails.
- **Wrong payment_method per store** — multi-store deployments need a PaymentMethod per store unless you explicitly mark it shared.

Always re-fetch the gateway gem's README before writing integration code — gateway APIs and Spree wrapper versions drift independently.

Related Skills

woo-payments

17
from OrcaQubits/agentic-commerce-skills-plugins

Build WooCommerce payment gateways — WC_Payment_Gateway, direct/redirect/hosted integrations, tokenization, subscriptions support, refunds, and PCI compliance. Use when creating custom payment method integrations.

spree-upgrades

17
from OrcaQubits/agentic-commerce-skills-plugins

Upgrade a Spree application — version-to-version migration paths (v4 → v5 is a major rewrite; v5.x → v5.y are simpler), Gemfile pinning strategy, decorator brittleness across versions, deprecated gems to remove (`spree_auth_devise`, `deface`, `spree_backend`), API v2 → v3 migration via `spree_legacy_api_v2`, admin Bootstrap → Tailwind transition, the upgrade guide workflow, and rollback strategy. Use when planning a Spree upgrade or auditing technical debt blocking one.

spree-typescript-sdk

17
from OrcaQubits/agentic-commerce-skills-plugins

Build storefronts and integrations using `@spree/sdk` — the official TypeScript SDK for Spree's API v3 (v5.4+). Covers installation, the resource-builder pattern (`spree.products.list`, `spree.checkout.create`, etc.), Zod schema validation, server-only auth (httpOnly JWTs, never exposing API keys), error handling, typing customizations, and pinning SDK versions to backend Spree releases. Use when integrating Spree into a Next.js / Node.js / TypeScript project.

spree-testing

17
from OrcaQubits/agentic-commerce-skills-plugins

Test Spree applications and extensions with RSpec — `spree_dev_tools` gem (v5.2+) for factories and helpers, FactoryBot patterns (prefer `build` over `create`), Capybara feature specs, controller/request specs, testing decorators and subscribers, dummy app for extension testing, system specs for the Hotwire admin, and CI patterns. Use when writing Spree tests, setting up CI, or refactoring slow specs.

spree-shipping-fulfillment

17
from OrcaQubits/agentic-commerce-skills-plugins

Build and customize Spree's shipping and fulfillment — ShippingMethod, ShippingCategory, Zone/ZoneMember, ShippingRate, the Stock::Estimator service, StockLocation/StockItem/StockMovement, multi-shipment orders, ShippingCalculator classes (FlatRate, FlatPercentItemTotal, PerItem, FlexiRate), shipment state machine, returns (ReturnAuthorization → CustomerReturn → Reimbursement → Refund), and integrating carrier APIs (UPS, FedEx, ShipStation). Use when configuring shipping rules, building fulfillment integrations, or debugging shipping-rate calculations.

spree-setup

17
from OrcaQubits/agentic-commerce-skills-plugins

Bootstrap a new Spree project — `create-spree-app` CLI (v5.2+), `spree-starter` Rails backend, the Next.js storefront repo, `bin/rails g spree:install`, sample data, Docker Compose, and the PostgreSQL + Redis + Sidekiq prerequisites. Use when starting a new Spree project from scratch or onboarding an existing repo.

spree-security

17
from OrcaQubits/agentic-commerce-skills-plugins

Secure a Spree deployment — Rails credentials and env-var hygiene, Devise auth (Spree v5 ships it in-core; `spree_auth_devise` is archived), CanCanCan authorization rules, Doorkeeper OAuth2 scopes, Storefront publishable key vs admin API key, webhook HMAC verification, OWASP Top 10 for Rails (mass assignment, CSRF, SQL injection via Ransack, XSS, IDOR through prefixed IDs), PCI scope (Spree never touches raw cards thanks to gateway tokenization), and multi-store data isolation. Use when auditing a Spree app, hardening a deploy, or addressing a security incident.

spree-promotions

17
from OrcaQubits/agentic-commerce-skills-plugins

Build and customize Spree's promotions engine — Promotion + PromotionRule + PromotionAction + CouponCode + Adjustment, the bundled rules (FirstOrder/ItemTotal/Product/Taxon/User/OneUsePerUser/Country/CustomerGroup/etc.), bundled actions (CreateAdjustment/CreateItemAdjustments/FreeShipping/CreateLineItems), Calculator classes, coupon batches with CSV export, the v5.1+ advanced rule-based engine, and authoring custom rules/actions/calculators. Use when modeling promotions, building discount UIs, or extending the promotions engine.

spree-performance

17
from OrcaQubits/agentic-commerce-skills-plugins

Profile and optimize a Spree application — N+1 queries with bullet/scout, database indexing strategy for Spree's polymorphic associations, Rails fragment + Russian doll caching, ActiveStorage variant pre-generation, Sidekiq queue tuning, MeiliSearch vs Postgres FTS tradeoffs, Puma worker/thread sizing, CDN strategy for catalog pages, asset precompile time, and load testing. Use when Spree is slow, the database is hot, or you're preparing for a traffic spike (Black Friday, launch).

spree-multi-store

17
from OrcaQubits/agentic-commerce-skills-plugins

Configure Spree for multi-store and multi-region commerce — one Rails install running many `Store` records, the v5.4+ `Market` model (currency + locale + payment methods + shipping per region), what's shared vs per-store (products+inventory+customers shared; orders+payments+themes per-store), the Marketplace module (Enterprise — vendors/commission/payouts via Stripe Connect), and the Multi-tenant SaaS model. Use when planning a multi-brand or multi-region Spree deployment.

spree-legacy-api-v2

17
from OrcaQubits/agentic-commerce-skills-plugins

Work with Spree's legacy v2 APIs — JSON:API-style Storefront API at `/api/v2/storefront/*` and Platform API at `/api/v2/platform/*`, Doorkeeper OAuth2 (password grant for storefront, client_credentials + admin scope for platform), the `spree_legacy_api_v2` gem (required in v5+ for backward compatibility), and migration patterns to API v3. Use when maintaining a v2 client during a migration window, integrating an older partner system, or deciding when to cut over to v3.

spree-i18n

17
from OrcaQubits/agentic-commerce-skills-plugins

Localize a Spree application — the `spree_i18n` gem with 60+ locale packs, the v5.4+ Translations Center for product/CMS content (CSV import/export), Rails i18n basics applied to Spree (translation files, locale switching, pluralization, interpolation), per-Market locale routing in the headless storefront, RTL languages, and translating extensions. Use when localizing a Spree store, adding a new locale, or building i18n-aware extensions.