---
title: Customers - Controller
description: List, retrieve and find `Customer` models.
---

To implement the `Customers` controller, you need to implement at least 2 API endpoints, we will use these endpoints to fetch customers from your system.

## Prerequisites
::grid{cols="2"}
    ::card-baseline{title="Customer Model" to="/integrations/models/customer"}
    A user who owns subscriptions.
      ::flex{class="mt-4"}
        :badge{label="Required" color="green"}
      ::
    ::
    ::card-baseline{title="Coupons - Controller" to="/integrations/controllers/coupons"}
    If you have customer-level discounts, you may need to implement a `Coupons` controller first.
      ::flex{class="mt-4"}
        :badge{label="Optional"} :badge{label="Discount Offer"}
      ::
    ::
::
## SDK

If you are using the SDK, you can implement the `Customers` 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 { Customer } from '../models/Customer'

export const Customers = Integrator.Customers.config({
    ctx: Context,
    async retrieve(ctx, options) {
        const yourCustomer = await ctx.db.findCustomerById(options.id)
        return new Customer(yourCustomer) 
    },
    async list(ctx, options) {
        const yourCustomers = await ctx.db.findCustomers({
            limit: options.limit,
            offset: options.cursor // the value you pass as `next` below
        })
        return {
            data: yourCustomers.map(c => new Customer(c)),
            // pass the next cursor if there are more items
            next: yourCustomers.length === options.limit ? offset + limit : undefined
        }
    },
    async findByEmail(ctx, email) { // optional
        const yourCustomer = await ctx.db.findCustomerByEmail(email)
        return new Customer(yourCustomer)
    },
    async findByPhone(ctx, phone) { // optional
        const yourCustomer = await ctx.db.findCustomerByPhone(phone)
        return new Customer(yourCustomer)
    }
})
```
::

## Endpoints

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

`GET /churnkey/customers/:id`

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

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

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

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

### List :badge{label="Optional"}
`GET /churnkey/customers`

This endpoint fetches a list of customers from your database. You should find customers in your database (with pagination), map them to the `Customer` 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 { Customer } from '../models/Customer'

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



### Find by Email :badge{label="Managed Flow"}
`GET /churnkey/customers/email/:email`

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

Make sure that each customer has a unique email address if you are going to implement this endpoint.

::collapsible{name="response"}
    ::tabs
        ::div{label="200"}
        Must return `Customer` model. See [Customer model documentation](/integrations/models/customer).
        ::
        ::div{label="Error"}
        See [Error Responses](/integrations/general#error-responses).
        ::
    ::
::
::collapsible{name="code example"}
    ::code-group
    ```typescript [Typescript Express]
    import { Customer } from '../models/Customer'

    app.get('/churnkey/customers/email/:email', async (req, res) => {
        const customer = await db.findCustomerByEmail(req.params.email)
        if (!customer) {
            return res.status(404).send({ code: 404, message: 'Customer not found' })
        }
        res.send(new Customer(customer))
    })
    ```
    ::
::

### Find by Phone :badge{label="Managed Flow"}
`GET /churnkey/customers/phone/:phone`

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

Make sure that each customer has a unique phone number if you are going to implement this endpoint.

::collapsible{name="response"}
    ::tabs
        ::div{label="200"}
        Must return `Customer` model. See [Customer model documentation](/integrations/models/customer).
        ::
        ::div{label="Error"}
        See [Error Responses](/integrations/general#error-responses).
        ::
    ::
::
::collapsible{name="code example"}
    ::code-group
    ```typescript [Typescript Express]
    import { Customer } from '../models/Customer'

    app.get('/churnkey/customers/email/:email', async (req, res) => {
        const customer = await db.findCustomerByEmail(req.params.email)
        if (!customer) {
            return res.status(404).send({ code: 404, message: 'Customer not found' })
        }
        res.send(new Customer(customer))
    })
    ```
    ::
::

## Webhooks
Coming soon.