# Custom integration

A custom integration is how your own code sends data to Summerbase. It is a [source](/docs/integrations.md): everything your code sends is recorded as coming from it, under its own slug. It does one of two jobs:

- **Add details to customers your billing system already sent.** Your billing is in Stripe, say, but your own system knows more: the plan tier in your product, the account manager, the industry. Your code adds that to the customers Stripe reported.
- **Send your subscriptions.** Your billing runs on a system Summerbase doesn't connect to, or on your own. Your code sends customers and their subscriptions, and Summerbase works out your metrics from them.

Both start the same way.

## Set up

1. **Create the integration.** Go to **Settings**, then **Integrations**, choose **Add integration**, then **Custom**. Give it a name and a short slug, such as `backend`. The slug can't be changed later, because your records are named with it: your customer `acct_4821` becomes `backend:acct_4821` in Summerbase, and your code uses that id to address it.
2. **Create an API key.** On the integration's page, under **API keys**, choose **New key**. Copy the secret straight away: it's shown only once. Keep it on your server. Everything the key sends is recorded as coming from this source, which is why an API key has a `source_id`.

## Add details to customers from another source

Address the customer by your own id, and list the id your billing system uses for them under `identities`. That links the two, and your properties land on the same customer:

```sh
curl https://api.summerbase.com/v1/customers/backend:acct_4821 \
  -X PATCH \
  -H "Authorization: Bearer $SUMMERBASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "identities": ["stripe:cus_NfJG2nK3"],
    "properties": {
      "account_manager": "Dana Okafor",
      "industry": "Logistics"
    }
  }'
```

From then on, either id finds the customer. Your properties are kept under your source, separately from Stripe's, so neither overwrites the other: the API shows them as `properties_by_source.backend` next to `properties_by_source.stripe`. For promoted fields such as the name and email, a custom integration's value beats Stripe's by default. See [How your data fits together](/docs/using-summerbase/how-your-data-fits-together.md).

You can add properties to a subscription the same way, addressed by the id Stripe has for it:

```sh
curl https://api.summerbase.com/v1/subscriptions/stripe:sub_1QxR8t \
  -X PATCH \
  -H "Authorization: Bearer $SUMMERBASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"properties": {"sales_channel": "partner"}}'
```

The subscription's amounts, status and dates stay with its owner source, Stripe here. If Stripe hasn't sent the subscription yet, the request is refused; send it again later.

## Send your subscriptions

### 1. Send a customer

Address each customer by your own id. Summerbase creates the customer the first time, and updates it after that.

```sh
curl https://api.summerbase.com/v1/customers/backend:acct_4821 \
  -X PATCH \
  -H "Authorization: Bearer $SUMMERBASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "name": "Northwind Labs",
      "email": "billing@northwind.example.com"
    }
  }'
```

### 2. Send your plans and prices

A subscription is on a price, and every price is on a plan, so both have to exist before a subscription names them. See [Plans and prices](/docs/using-summerbase/how-your-data-fits-together.md#plans-and-prices).

First the plan, addressed by your own id for it. Summerbase creates it the first time, and updates it after that:

```sh
curl https://api.summerbase.com/v1/plans/backend:growth \
  -X PATCH \
  -H "Authorization: Bearer $SUMMERBASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "name": "Growth",
      "archived": false
    }
  }'
```

Then each price on it, naming the plan with `plan_id`. A name and the price's list terms are optional:

```sh
curl https://api.summerbase.com/v1/prices/backend:growth_monthly \
  -X PATCH \
  -H "Authorization: Bearer $SUMMERBASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "plan_id": "backend:growth",
    "name": "Growth monthly",
    "currency_code": "USD",
    "interval": "month",
    "interval_count": 1,
    "pricing_model": "fixed",
    "unit_amount": "50.00"
  }'
```

An annual Growth price is a second price with the same `plan_id`.

### 3. Send a subscription

Each item names its price with `price_id`. The plan comes from the price.

```sh
curl https://api.summerbase.com/v1/subscriptions/backend:sub_311 \
  -X PATCH \
  -H "Authorization: Bearer $SUMMERBASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "claim_ownership": true,
    "customer_id": "backend:acct_4821",
    "status": "active",
    "currency_code": "USD",
    "items": [
      {
        "id": "backend:item_9001",
        "price_id": "backend:growth_monthly",
        "unit_amount": "50.00",
        "quantity": "25",
        "interval": "month"
      }
    ]
  }'
```

`claim_ownership: true` is needed the first time you send a subscription. It makes your source the subscription's owner source (`owner_source_id` in the API): the one it's billed through. From then on, only your source can change its amounts, status and dates.

The order matters: plans, then prices, then subscriptions. A subscription that names a price Summerbase doesn't have yet is refused as a whole.

### 4. Keep it up to date

Whenever something changes, such as a move to another price, more seats or a cancellation, send the subscription again with what's true now. A new price goes in before the first subscription on it. Sending the same thing twice is harmless.

To load the history you had before using Summerbase, see [Reimport subscription](/docs/api/operations/reimport-subscription).

## Next

The [API reference](/docs/api) has every endpoint and field.

## For AI agents

If you're an AI agent writing this integration for someone:

- The [API reference](/docs/api) explains every endpoint, with examples.
- The OpenAPI spec, [`https://api.summerbase.com/v1/open_api`](https://api.summerbase.com/v1/open_api), has every endpoint's exact request and response, to check a call against or generate a client from.
- Read the integration's key from the person's environment or secrets. Don't ask them to paste it into the chat.
