> ## Documentation Index
> Fetch the complete documentation index at: https://spreecommerce.org/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Customizing the Spree API

> Add new Store API endpoints, customize existing JSON responses with serializer decorators, and extend Spree's REST API to fit your storefront needs.

Before you start customizing Spree API endpoints, make sure you reviewed all existing API endpoints in the [Spree API docs](/api-reference).

For a step-by-step walkthrough of adding a complete new resource (model, serializer, controller, routes), see the [API tutorial](/developer/tutorial/api).

## Customizing JSON Responses

Spree uses [Alba](https://github.com/okuramasafumi/alba) serializers to build API v3 responses. You can replace any serializer via [Spree Dependencies](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:

```ruby app/serializers/my_app/product_serializer.rb theme={"theme":"night-owl"}
module MyApp
  class ProductSerializer < Spree::Api::V3::ProductSerializer
    attribute :my_custom_attribute
  end
end
```

Register it in `config/initializers/spree.rb`:

```ruby theme={"theme":"night-owl"}
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](/developer/tutorial/api) for the full example).

Create a serializer for the new model:

```ruby app/serializers/spree/api/v3/brand_serializer.rb theme={"theme":"night-owl"}
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:

```ruby app/serializers/my_app/product_serializer.rb theme={"theme":"night-owl"}
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`:

```ruby theme={"theme":"night-owl"}
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:

| Key                      | Default                                 |
| ------------------------ | --------------------------------------- |
| `product_serializer`     | `Spree::Api::V3::ProductSerializer`     |
| `variant_serializer`     | `Spree::Api::V3::VariantSerializer`     |
| `cart_serializer`        | `Spree::Api::V3::CartSerializer`        |
| `order_serializer`       | `Spree::Api::V3::OrderSerializer`       |
| `line_item_serializer`   | `Spree::Api::V3::LineItemSerializer`    |
| `category_serializer`    | `Spree::Api::V3::CategorySerializer`    |
| `customer_serializer`    | `Spree::Api::V3::CustomerSerializer`    |
| `address_serializer`     | `Spree::Api::V3::AddressSerializer`     |
| `payment_serializer`     | `Spree::Api::V3::PaymentSerializer`     |
| `fulfillment_serializer` | `Spree::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:

```ruby app/controllers/spree/api/v3/store/brands_controller.rb theme={"theme":"night-owl"}
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:

| Feature       | How                                                                               |
| ------------- | --------------------------------------------------------------------------------- |
| Pagination    | [Pagy](https://github.com/ddnexus/pagy) — `?page=2&limit=25`                      |
| Filtering     | [Ransack](https://github.com/activerecord-hackery/ransack) — `?q[name_cont]=nike` |
| Sorting       | JSON:API style — `?sort=-name`                                                    |
| Authorization | [CanCanCan](https://github.com/CanCanCommunity/cancancan)                         |
| Prefixed IDs  | Stripe-style — `brand_k5nR8xLq`                                                   |

Override these methods to customize:

| Method                | Purpose                                |
| --------------------- | -------------------------------------- |
| `model_class`         | ActiveRecord model (required)          |
| `serializer_class`    | Alba serializer (required)             |
| `scope`               | Base query — add `.where()` to filter  |
| `find_resource`       | Custom ID lookup (slug fallback, etc.) |
| `permitted_params`    | Custom strong params                   |
| `collection_includes` | Eager loading for `index`              |

### Routes

Add routes in your app's `config/routes.rb`:

```ruby theme={"theme":"night-owl"}
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:

```ruby config/initializers/spree.rb theme={"theme":"night-owl"}
Spree::PermittedAttributes.brand_attributes = [:name, :slug, :description, :logo]
```

Or override `permitted_params` in the controller:

```ruby theme={"theme":"night-owl"}
def permitted_params
  params.permit(:name, :slug, :description, :logo)
end
```

## Consuming Custom Endpoints with the SDK

See the [SDK tutorial](/developer/tutorial/sdk) for how to call custom endpoints from TypeScript and extend the generated types.
