Skip to main content
Before you start customizing Spree API endpoints, make sure you reviewed all existing API endpoints in the Spree API docs. For a step-by-step walkthrough of adding a complete new resource (model, serializer, controller, routes), see the Store API tutorial.

Customizing JSON Responses

Spree uses Alba serializers to build API v3 responses. You can replace any serializer via Spree Dependencies.

Adding Custom Attributes

Let’s say you want to add a my_custom_attribute column to the Product API response. Create a custom serializer that inherits from the core one:
app/serializers/my_app/product_serializer.rb
module MyApp
  class ProductSerializer < Spree::Api::V3::ProductSerializer
    attribute :my_custom_attribute
  end
end
Register it in config/initializers/spree.rb:
Spree::Api::Dependencies.product_serializer = 'MyApp::ProductSerializer'
Restart the server and the Product API will include your new attribute.

Adding an Association

Let’s say you’ve created a Spree::Brand model that belongs to Product (see the tutorial for the full example). Create a serializer for the new model:
app/serializers/spree/api/v3/brand_serializer.rb
module Spree
  module Api
    module V3
      class BrandSerializer < BaseSerializer
        typelize name: :string, slug: [:string, nullable: true]

        attributes :name, :slug
      end
    end
  end
end
Then subclass the Product serializer to include the brand association:
app/serializers/my_app/product_serializer.rb
module MyApp
  class ProductSerializer < Spree::Api::V3::ProductSerializer
    typelize brand_id: [:string, nullable: true]

    attribute :brand_id do |product|
      product.brand&.prefixed_id
    end

    one :brand,
        resource: Spree::Api::V3::BrandSerializer,
        if: proc { expand?('brand') }
  end
end
Register it in config/initializers/spree.rb:
Spree::Api::Dependencies.product_serializer = 'MyApp::ProductSerializer'
The brand data is available via ?expand=brand:
GET /api/v3/store/products/prod_86Rf07xd4z?expand=brand

Serializer Dependency Keys

Here are the most commonly customized v3 serializers:
KeyDefault
product_serializerSpree::Api::V3::ProductSerializer
variant_serializerSpree::Api::V3::VariantSerializer
cart_serializerSpree::Api::V3::CartSerializer
order_serializerSpree::Api::V3::OrderSerializer
line_item_serializerSpree::Api::V3::LineItemSerializer
category_serializerSpree::Api::V3::CategorySerializer
customer_serializerSpree::Api::V3::CustomerSerializer
address_serializerSpree::Api::V3::AddressSerializer
payment_serializerSpree::Api::V3::PaymentSerializer
fulfillment_serializerSpree::Api::V3::FulfillmentSerializer
See Spree::Api::ApiDependencies for the full list.

Adding New Endpoints

Controller

Inherit from Spree::Api::V3::Store::ResourceController for Store API endpoints:
app/controllers/spree/api/v3/store/brands_controller.rb
module Spree
  module Api
    module V3
      module Store
        class BrandsController < ResourceController
          protected

          def model_class
            Spree::Brand
          end

          def serializer_class
            Spree::Api::V3::BrandSerializer
          end

          def scope
            Spree::Brand.all
          end
        end
      end
    end
  end
end
The base ResourceController provides:
FeatureHow
PaginationPagy?page=2&limit=25
FilteringRansack?q[name_cont]=nike
SortingJSON:API style — ?sort=-name
AuthorizationCanCanCan
Prefixed IDsStripe-style — brand_k5nR8xLq
Override these methods to customize:
MethodPurpose
model_classActiveRecord model (required)
serializer_classAlba serializer (required)
scopeBase query — add .where() to filter
find_resourceCustom ID lookup (slug fallback, etc.)
permitted_paramsCustom strong params
collection_includesEager loading for index

Routes

Add routes in your app’s config/routes.rb:
Spree::Core::Engine.add_routes do
  namespace :api, defaults: { format: 'json' } do
    namespace :v3 do
      namespace :store do
        resources :brands, only: [:index, :show]
      end
    end
  end
end

Permitted Attributes

For endpoints that accept writes (create/update), add your attributes:
config/initializers/spree.rb
Spree::PermittedAttributes.brand_attributes = [:name, :slug, :description, :logo]
Or override permitted_params in the controller:
def permitted_params
  params.permit(:name, :slug, :description, :logo)
end

Consuming Custom Endpoints with the SDK

See the SDK tutorial for how to call custom endpoints from TypeScript and extend the generated types.