Terminal Products API
Lists Terminal's coffee products and their purchasable variants, with pricing (in cents), market availability, and subscription eligibility.
Lists Terminal's coffee products and their purchasable variants, with pricing (in cents), market availability, and subscription eligibility.
openapi: 3.0.1
info:
title: Terminal Shop API
description: >-
Public REST API for Terminal, a developer-focused coffee company. The API
powers product browsing, carts, orders, subscriptions, addresses, cards,
profiles, personal access tokens, and OAuth apps - the same surface behind
the `ssh terminal.shop` storefront and the official SDKs. All monetary
amounts are integers in US cents. Authentication is a Bearer personal
access token (`trm_live_*` in production, `trm_test_*` in the dev sandbox)
or an OAuth 2.0 access token.
termsOfService: https://www.terminal.shop/terms
contact:
name: Terminal Support
url: https://www.terminal.shop
version: '1.0'
servers:
- url: https://api.terminal.shop
description: Production
- url: https://api.dev.terminal.shop
description: Dev sandbox (no real charges)
security:
- bearerAuth: []
tags:
- name: Product
- name: Cart
- name: Order
- name: Subscription
- name: Address
- name: Card
- name: Profile
- name: Token
- name: App
- name: Email
- name: View
paths:
/product:
get:
operationId: listProducts
tags: [Product]
summary: List all products
description: List all products for sale in the Terminal shop.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: array
items:
$ref: '#/components/schemas/Product'
/product/{id}:
get:
operationId: getProduct
tags: [Product]
summary: Get product
description: Get a product by ID from the Terminal shop.
parameters:
- $ref: '#/components/parameters/PathID'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/Product'
/cart:
get:
operationId: getCart
tags: [Cart]
summary: Get cart
description: Get the current user's cart.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/Cart'
delete:
operationId: clearCart
tags: [Cart]
summary: Clear cart
description: Clear the current user's cart.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: string
description: Empty string on success.
/cart/item:
put:
operationId: setCartItem
tags: [Cart]
summary: Add or update cart item
description: Add an item to the current user's cart, or update its quantity.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [productVariantID, quantity]
properties:
productVariantID:
type: string
description: ID of the product variant to add.
quantity:
type: integer
format: int64
description: Quantity of the item. Set to 0 to remove it.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/Cart'
/cart/address:
put:
operationId: setCartAddress
tags: [Cart]
summary: Set cart shipping address
description: Set the shipping address for the current user's cart.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [addressID]
properties:
addressID:
type: string
description: ID of the saved shipping address.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: string
/cart/card:
put:
operationId: setCartCard
tags: [Cart]
summary: Set cart payment card
description: Set the payment card for the current user's cart.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [cardID]
properties:
cardID:
type: string
description: ID of the saved payment card.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: string
/cart/convert:
post:
operationId: convertCart
tags: [Cart]
summary: Convert cart to order
description: Convert the current user's cart to an order and place it.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/Order'
/order:
get:
operationId: listOrders
tags: [Order]
summary: List orders
description: List the orders associated with the current user.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: array
items:
$ref: '#/components/schemas/Order'
post:
operationId: createOrder
tags: [Order]
summary: Create order
description: >-
Create an order without a cart. The order is placed immediately using
the supplied address, card, and variant quantities.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [addressID, cardID, variants]
properties:
addressID:
type: string
description: ID of the shipping address.
cardID:
type: string
description: ID of the payment card.
variants:
type: object
description: Map of product variant ID to quantity.
additionalProperties:
type: integer
format: int64
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: string
description: ID of the created order.
/order/{id}:
get:
operationId: getOrder
tags: [Order]
summary: Get order
description: Get the order with the given ID.
parameters:
- $ref: '#/components/parameters/PathID'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/Order'
/subscription:
get:
operationId: listSubscriptions
tags: [Subscription]
summary: List subscriptions
description: List the subscriptions associated with the current user.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: array
items:
$ref: '#/components/schemas/Subscription'
post:
operationId: createSubscription
tags: [Subscription]
summary: Create subscription
description: Create a subscription for the current user.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SubscriptionInput'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: string
/subscription/{id}:
get:
operationId: getSubscription
tags: [Subscription]
summary: Get subscription
description: Get the subscription with the given ID.
parameters:
- $ref: '#/components/parameters/PathID'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/Subscription'
put:
operationId: updateSubscription
tags: [Subscription]
summary: Update subscription
description: Update the subscription with the given ID.
parameters:
- $ref: '#/components/parameters/PathID'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
addressID:
type: string
cardID:
type: string
schedule:
$ref: '#/components/schemas/SubscriptionSchedule'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/Subscription'
delete:
operationId: deleteSubscription
tags: [Subscription]
summary: Cancel subscription
description: Cancel the subscription with the given ID.
parameters:
- $ref: '#/components/parameters/PathID'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: string
/address:
get:
operationId: listAddresses
tags: [Address]
summary: List addresses
description: Get the shipping addresses associated with the current user.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: array
items:
$ref: '#/components/schemas/Address'
post:
operationId: createAddress
tags: [Address]
summary: Create address
description: Create and add a shipping address to the current user.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AddressInput'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: string
description: ID of the created address.
/address/{id}:
get:
operationId: getAddress
tags: [Address]
summary: Get address
description: Get the shipping address with the given ID.
parameters:
- $ref: '#/components/parameters/PathID'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/Address'
delete:
operationId: deleteAddress
tags: [Address]
summary: Delete address
description: Delete a shipping address from the current user.
parameters:
- $ref: '#/components/parameters/PathID'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: string
/card:
get:
operationId: listCards
tags: [Card]
summary: List cards
description: List the credit cards associated with the current user.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: array
items:
$ref: '#/components/schemas/Card'
post:
operationId: createCard
tags: [Card]
summary: Create card
description: >-
Attach a credit card (via a Stripe token) to the current user.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [token]
properties:
token:
type: string
description: Stripe card token.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: string
description: ID of the created card.
/card/collect:
post:
operationId: collectCard
tags: [Card]
summary: Collect card
description: >-
Create a temporary URL for collecting credit card information on a
Stripe-hosted page.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: object
required: [url]
properties:
url:
type: string
format: uri
description: Hosted card-collection URL.
/card/{id}:
get:
operationId: getCard
tags: [Card]
summary: Get card
description: Get the credit card with the given ID.
parameters:
- $ref: '#/components/parameters/PathID'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/Card'
delete:
operationId: deleteCard
tags: [Card]
summary: Delete card
description: Delete a credit card associated with the current user.
parameters:
- $ref: '#/components/parameters/PathID'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: string
/profile:
get:
operationId: getProfile
tags: [Profile]
summary: Get profile
description: Get the current user's profile.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/Profile'
put:
operationId: updateProfile
tags: [Profile]
summary: Update profile
description: Update the current user's name and email.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, email]
properties:
name:
type: string
email:
type: string
format: email
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/Profile'
/token:
get:
operationId: listTokens
tags: [Token]
summary: List tokens
description: List the personal access tokens associated with the current user.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: array
items:
$ref: '#/components/schemas/Token'
post:
operationId: createToken
tags: [Token]
summary: Create token
description: >-
Create a personal access token. The secret is returned only once at
creation time.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: object
required: [id, token]
properties:
id:
type: string
token:
type: string
description: The token secret (shown once).
/token/{id}:
get:
operationId: getToken
tags: [Token]
summary: Get token
description: Get the personal access token with the given ID.
parameters:
- $ref: '#/components/parameters/PathID'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/Token'
delete:
operationId: deleteToken
tags: [Token]
summary: Delete token
description: Delete the personal access token with the given ID.
parameters:
- $ref: '#/components/parameters/PathID'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: string
/app:
get:
operationId: listApps
tags: [App]
summary: List apps
description: List the OAuth apps associated with the current user.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: array
items:
$ref: '#/components/schemas/App'
post:
operationId: createApp
tags: [App]
summary: Create app
description: Create an OAuth app. The client secret is returned only at creation.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, redirectURI]
properties:
name:
type: string
redirectURI:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: object
required: [id, secret]
properties:
id:
type: string
secret:
type: string
/app/{id}:
get:
operationId: getApp
tags: [App]
summary: Get app
description: Get the OAuth app with the given ID.
parameters:
- $ref: '#/components/parameters/PathID'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/App'
delete:
operationId: deleteApp
tags: [App]
summary: Delete app
description: Delete the OAuth app with the given ID.
parameters:
- $ref: '#/components/parameters/PathID'
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: string
/email:
post:
operationId: createEmail
tags: [Email]
summary: Subscribe email
description: Subscribe to email updates from Terminal.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [email]
properties:
email:
type: string
format: email
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
type: string
/view/init:
get:
operationId: initView
tags: [View]
summary: Get app data
description: >-
Get all data needed to render the Terminal storefront app in a single
request - region plus the current user's products, profile, addresses,
cards, cart, orders, subscriptions, tokens, and apps.
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/InitView'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: >-
Personal access token (`trm_live_*` in production, `trm_test_*` in the
dev sandbox) or OAuth 2.0 access token, passed as
`Authorization: Bearer <token>`.
parameters:
PathID:
name: id
in: path
required: true
schema:
type: string
schemas:
Product:
type: object
required: [id, name, description, variants]
properties:
id:
type: string
name:
type: string
description:
type: string
variants:
type: array
items:
$ref: '#/components/schemas/ProductVariant'
order:
type: integer
format: int64
description: Sort order of the product.
subscription:
type: string
enum: [allowed, required]
description: Whether subscriptions are allowed or required for this product.
tags:
$ref: '#/components/schemas/ProductTags'
ProductVariant:
type: object
required: [id, name, price]
properties:
id:
type: string
name:
type: string
price:
type: integer
format: int64
description: Price of the variant in US cents.
tags:
type: object
additionalProperties: true
ProductTags:
type: object
properties:
app:
type: string
color:
type: string
featured:
type: boolean
market_eu:
type: boolean
market_global:
type: boolean
market_na:
type: boolean
Cart:
type: object
required: [items, subtotal, amount]
properties:
items:
type: array
items:
$ref: '#/components/schemas/CartItem'
subtotal:
type: integer
format: int64
description: Subtotal of the items in the cart, in cents.
amount:
$ref: '#/components/schemas/CartAmount'
addressID:
type: string
cardID:
type: string
shipping:
$ref: '#/components/schemas/CartShipping'
CartItem:
type: object
required: [id, productVariantID, quantity, subtotal]
properties:
id:
type: string
productVariantID:
type: string
quantity:
type: integer
format: int64
subtotal:
type: integer
format: int64
CartAmount:
type: object
required: [subtotal]
properties:
subtotal:
type: integer
format: int64
shipping:
type: integer
format: int64
total:
type: integer
format: int64
CartShipping:
type: object
properties:
service:
type: string
timeframe:
type: string
Order:
type: object
required: [id, amount, created, items, shipping, tracking]
properties:
id:
type: string
amount:
$ref: '#/components/schemas/OrderAmount'
created:
type: string
items:
type: array
items:
$ref: '#/components/schemas/OrderItem'
shipping:
$ref: '#/components/schemas/OrderShipping'
tracking:
$ref: '#/components/schemas/OrderTracking'
index:
type: integer
format: int64
OrderAmount:
type: object
required: [shipping, subtotal]
properties:
shipping:
type: integer
format: int64
subtotal:
type: integer
format: int64
OrderItem:
type: object
required: [id, amount, quantity]
properties:
id:
type: string
amount:
type: integer
format: int64
quantity:
type: integer
format: int64
description:
type: string
productVariantID:
type: string
OrderShipping:
type: object
required: [city, country, name, street1, zip]
properties:
city:
type: string
country:
type: string
name:
type: string
street1:
type: string
street2:
type: string
zip:
type: string
province:
type: string
phone:
type: string
OrderTracking:
type: object
properties:
number:
type: string
service:
type: string
status:
type: string
enum: [PRE_TRANSIT, TRANSIT, DELIVERED, RETURNED, FAILURE, UNKNOWN]
statusDetails:
type: string
statusUpdatedAt:
type: string
url:
type: string
Subscription:
type: object
required: [id, productVariantID, quantity, addressID, cardID, created, price]
properties:
id:
type: string
productVariantID:
type: string
quantity:
type: integer
format: int64
addressID:
type: string
cardID:
type: string
created:
type: string
price:
type: integer
format: int64
description: Price of the subscription line in cents.
next:
type: string
description: Next scheduled order date.
schedule:
$ref: '#/components/schemas/SubscriptionSchedule'
SubscriptionInput:
type: object
required: [productVariantID, quantity, addressID, cardID]
properties:
productVariantID:
type: string
quantity:
type: integer
format: int64
addressID:
type: string
cardID:
type: string
schedule:
$ref: '#/components/schemas/SubscriptionSchedule'
SubscriptionSchedule:
oneOf:
- type: object
required: [type]
properties:
type:
type: string
enum: [fixed]
interval:
type: integer
format: int64
- type: object
required: [type, interval]
properties:
type:
type: string
enum: [weekly]
interval:
type: integer
format: int64
description: Number of weeks between orders.
Address:
type: object
required: [id, city, country, created, name, street1, zip]
properties:
id:
type: string
city:
type: string
country:
type: string
created:
type: string
name:
type: string
street1:
type: string
street2:
type: string
zip:
type: string
province:
type: string
phone:
type: string
AddressInput:
type: object
required: [city, country, name, street1, zip]
properties:
city:
type: string
country:
type: string
name:
type: string
street1:
type: string
street2:
type: string
zip:
type: string
province:
type: string
phone:
type: string
Card:
type: object
required: [id, brand, created, expiration, last4]
properties:
id:
type: string
brand:
type: string
created:
type: string
last4:
type: string
expiration:
$ref: '#/components/schemas/CardExpiration'
CardExpiration:
type: object
required: [month, year]
properties:
month:
type: integer
format: int64
year:
type: integer
format: int64
Profile:
type: object
required: [user]
properties:
user:
type: object
required: [id, email, fingerprint, name, stripeCustomerID]
properties:
id:
type: string
email:
type: string
nullable: true
fingerprint:
type: str
# --- truncated at 32 KB (33 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/terminal-shop/refs/heads/main/openapi/terminal-shop-openapi.yml