Skip to content

Create a subscription

POST
/v1/subscriptions
curl -X POST "https://api.summerbase.com/v1/subscriptions" \
-H "Authorization: Bearer sb_..." \
-H "Content-Type: application/json" \
-d '{
"claim_ownership": true,
"currency_code": "USD",
"current_period_ends_at": "2026-11-01T10:04:00Z",
"customer_id": "backend:acct_4821",
"items": [
{
"id": "backend:item_9001",
"interval": "month",
"price_id": "backend:growth-monthly",
"quantity": "25",
"unit_amount": "50.00"
}
],
"status": "active"
}'

Creates a subscription. Your source owns it, and is the only one that may move its status, its dates or its items afterwards — which is why it takes claim_ownership: true.

A Summerbase id is assigned to it, which is what a subscription billed outside any system that would give it one needs. Naming one of your own ids instead creates it under that name.

expand[]
Array<string>
<= 10 items
Allowed values: currency customer items owner_source

Relationships to include in the response instead of fetching separately. A dotted path expands what an expanded record can expand in turn — at most 4 deep, 10 paths a request, and never back to a record already on the path.

Media typeapplication/json
object
cancels_at

A cancellation already booked. It is still in service until then, and the source says so with status: canceled when it stops.

string format: date-time
claim_ownership

Say true to create this subscription as the source it lives in — the only one that may write its status, its dates and its items from then on. A subscription is never created without it, so a write meant to annotate one that does not exist yet is refused rather than creating it under the wrong owner. On an existing subscription it changes nothing for the owner and is refused for anyone else.

boolean
currency_code
required

The currency it bills in, by its ISO 4217 code.

string
>= 3 characters <= 3 characters
current_period_ends_at

When the current billing period ends. The next charge is due then, unless a cancellation is booked for it.

string format: date-time
customer_id
required

Who is subscribed. A Summerbase id, or any source identity for them like stripe:cus_123, which creates the customer if it is new.

string
ended_at

When service stopped, beside status: canceled. Clear it, with status back to active, to resume a subscription; the same id may be brought back as often as the source does so.

string format: date-time
items

The items it is made of.

Array<object>
object
discount_amount

What comes off this item’s invoice, as a decimal string, every coupon on it worked out. 0 is no discount, and clears one.

string format: decimal
discount_ends_at

When the discount, or the earliest part of it, stops applying, if known. Read with discount_amount: sent without it, an amount has no known end.

string format: date-time
id
required

This item’s id — a Summerbase id, or a source identity like stripe:si_123.

string
>= 1 characters <= 320 characters
identities

What other sources call this item, as source:id.

Array<string>
interval

The unit the item bills in.

string
Allowed values: day week month year
interval_count

How many intervals between charges. Two months is month with a count of 2.

integer
>= 1
price_id

The price this item is on — a Summerbase id, or a source identity like stripe:price_123. It has to exist: create it first, with PATCH /v1/prices/{id}. The item’s plan is the price’s.

string
<= 320 characters
pricing_model

How the unit amount is arrived at. fixed unless said otherwise.

string
Allowed values: fixed tiered metered
properties

Properties to record for this item, in your source.

object
key
additional properties
Any of:
string
quantity

How many units at this unit amount. A decimal string; 1.5 is allowed.

string format: decimal
unit_amount

What one unit costs per interval, as a decimal string. Excludes tax and discounts.

string format: decimal
on_warning

What to do about the parts of this write that cannot be applied as sent, or that would merge two records together.

warn applies everything it can and reports the rest in warnings, so one unusable property never costs you a subscription’s amounts. error applies none of it unless all of it applies: the write is rolled back and every warning comes back as an error instead.

Send error from a form, where somebody is waiting to be told what to fix, and where folding two customers together is a thing to confirm rather than to discover afterwards. Leave it alone in an ingest client, which wants the revenue to land either way.

string
Allowed values: warn error
properties

Properties to record in your source.

Property keys and the values to set. Only the keys named here change; null clears one.

object
key
additional properties
Any of:
string
status
required

Where it is in its life. Not whether it has been paid for.

string
Allowed values: pending trialing active paused canceled
trial_ends_at

When the trial ends, or ended. A subscription that trials starts trialing, so when it began is started_at and its status history.

string format: date-time

Example

{
"claim_ownership": true,
"currency_code": "USD",
"current_period_ends_at": "2026-11-01T10:04:00Z",
"customer_id": "backend:acct_4821",
"items": [
{
"id": "backend:item_9001",
"interval": "month",
"price_id": "backend:growth-monthly",
"quantity": "25",
"unit_amount": "50.00"
}
],
"status": "active"
}

Returns the subscription object, with response_metadata about this request.

Media typeapplication/json
object
response_metadata

About this request rather than about the record. Absent when there is nothing to say.

object
warnings

Parts of this write that were skipped — a property whose value did not fit its type — and things it did that were worth saying, like merging two customers. The rest of the write landed. Absent when there is nothing to report.

Send on_warning: "error" to have these refuse the write instead, and come back as error.errors with the same codes.

Array<object>
object
code
required

What kind of thing was skipped, for a client to branch on.

string
field

The input it came from, like properties.seats.

string
message
required

What was skipped and why, in a sentence.

string

Example

{
"annual_amount": "15000.00",
"billing_amounts": [
{
"interval": "month",
"interval_count": 1,
"net_amount": "1250.00"
}
],
"cancels_at": null,
"currency_code": "USD",
"current_period_ends_at": "2026-11-01T10:04:00Z",
"customer_id": "0199a7c2-4e1b-7f38-b9d2-5a6c8e0f1d73",
"ended_at": null,
"id": "0199a7c2-5b3e-7a14-8c6d-2f9e4b7a1c05",
"identities": [
"stripe:sub_1QhT5uV7wX9yZ2aB"
],
"monthly_amount": "1250.00",
"object": "subscription",
"owner_source_id": "0198f1a3-0b7c-7e25-9f41-6a2d8c3e5b19",
"properties": {
"account_manager": "Priya Shah"
},
"properties_by_source": {
"backend": {
"account_manager": "Priya Shah"
},
"stripe": {
"contract_id": "C-2025-118"
}
},
"recorded_at": "2025-11-17T10:04:03Z",
"started_at": "2025-11-17T10:04:00Z",
"status": "active",
"trial_ends_at": "2025-12-01T10:04:00Z"
}