> ## 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.

# API

> Add new Store API endpoints and customize existing API responses

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 [Store API tutorial](/developer/tutorial/store-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/store-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.
