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 `. 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: string nullable: true name: type: string nullable: true stripeCustomerID: type: string Token: type: object required: [id, token, created] properties: id: type: string token: type: string description: Masked or full token identifier. created: type: string App: type: object required: [id, name, redirectURI, secret] properties: id: type: string name: type: string redirectURI: type: string secret: type: string InitView: type: object required: - region - products - profile - addresses - cards - cart - orders - subscriptions - tokens - apps properties: region: type: string enum: [eu, na] products: type: array items: $ref: '#/components/schemas/Product' profile: $ref: '#/components/schemas/Profile' addresses: type: array items: $ref: '#/components/schemas/Address' cards: type: array items: $ref: '#/components/schemas/Card' cart: $ref: '#/components/schemas/Cart' orders: type: array items: $ref: '#/components/schemas/Order' subscriptions: type: array items: $ref: '#/components/schemas/Subscription' tokens: type: array items: $ref: '#/components/schemas/Token' apps: type: array items: $ref: '#/components/schemas/App'