---
title: Coupons - Controller
description: List and retrieve `Coupon` models.
---

To implement the `Coupons` controller, you need to implement 2 API endpoints, we will use these endpoints to fetch coupons from your system.

## Prerequisites
::grid{cols="2"}
    ::card-baseline{title="Coupon Model" to="/integrations/models/coupon"}
      A code that can be redeemed for a discount.
      ::flex{class="mt-4"}
        :badge{label="Required" color="green"}
      ::
    ::
::

## SDK

If you are using the SDK, you can implement the `Coupons` controller by following the code example below. You don't need to get into the details of the API endpoints, the SDK will take care of that for you.

::code-group
```typescript [Typescript]
import { Integrator } from '@churnkey/sdk'
import { Context } from '../Context'
import { Coupon } from '../models/Coupon'

export const Coupons = Integrator.Coupons.config({
    ctx: Context,
    async retrieve(ctx, options) {
        const yourCoupon = await ctx.db.findCoupon(options.id)
        return new Coupon(yourCoupon)
    },
    async list(ctx, options) {
        const yourCoupons = await ctx.db.listCoupons({
            limit: options.limit,
            offset: options.cursor // the value you pass as `next` below
        })
        return {
            data: yourCoupons.map(coupon => new Coupon(coupon)),
            // pass the next cursor if there are more items
            next: yourCoupons.length === options.limit ? offset + limit : undefined
        }
    }
})
```
::

## Endpoints

###  Retrieve :badge{label="Required" color="green"}

`GET /churnkey/coupons/:id`

This endpoint fetches `Coupon` by its `id`. Usually, implementation will include finding a coupon in your database and mapping it to the [Coupon model](/integrations/models/coupon).

::collapsible{name="response"}
    ::tabs
        ::div{label="200"}
        Must return `Coupon` model. See [Coupon model documentation](/integrations/models/coupon).
        ::
        ::div{label="Error"}
        See [Error Responses](/integrations/general#error-responses).
        ::
    ::
::

::collapsible{name="code example"}
    ::code-group
    ```typescript [Typescript Express]
    import { Coupon } from '../models/Coupon'

    app.get('/churnkey/coupons/:id', async (req, res) => {
        const coupon = await db.findCouponById(req.params.id)
        if (!coupon) {
            return res.status(404).send({ code: 404, message: 'Coupon not found' })
        }
        res.send(new Coupon(coupon))
    })
    ```
    ::
::

### List :badge{label="Required" color="green"}
`GET /churnkey/coupons`

This endpoint fetches a list of coupons from your database. You should find coupons in your database (with pagination), map them to the `Coupon` model and return a paginated list.

[Learn more about pagination](/integrations/general#pagination).

::collapsible{name="query parameters"}
  :field-schema{schema="/types/pagination-query.type"}
::
::collapsible{name="response"}
  :field-schema{schema="/types/pagination-response.type"}
::

::collapsible{name="code example"}
    ::code-group
    ```typescript [Typescript Express]
    import { Coupon } from '../models/Coupon'

    app.get('/churnkey/coupons', async (req, res) => {
        const limit = Number.parseInt(req.query.limit)
        const offset = Number.parseInt(req.query.cursor) 
        const coupons = await db.findCoupons({ limit, offset })
        res.send({
            data: coupons.map(c => new Coupon(c)),
            next: coupons.length === limit ? offset + limit : undefined
        })
    })
    ```
    ::
::


## Webhooks
Coming soon.
