Moosyl logo

Billing objects

Reference for the products, prices, customers and invoices behind Moosyl subscriptions: fields, endpoints and SDK methods.

Subscriptions are built from four objects. This page lists their fields and endpoints. For how they fit together over a billing cycle, read Subscriptions.

ObjectWhat it isScope
ProductSomething you sell on a schedule, like "Pro plan"Environment of the key that created it
PriceAn amount and interval for a productOrganization (through its product)
CustomerOne of your users, identified by your own user IDOrganization (shared by Sandbox and Production)
InvoiceA bill for one billing periodOrganization

All endpoints on this page need your secret key in the Authorization header, without Bearer. Base URL: https://api.moosyl.com. The full list of parameters and responses is in the API reference.

Lists and pagination

List endpoints accept page (default 1) and limit (default 20, max 100) and return:

{
  "data": [],
  "pagination": { "page": 1, "limit": 20, "total": 0, "totalPages": 0 }
}

Single-object endpoints return { "data": { ... } }. The SDK unwraps data for you.

Products

A product groups the prices you charge for one offer.

FieldTypeDescription
idstring (UUID)Product ID
namestringShown on your side; required
descriptionstring or nullOptional
activebooleanfalse once archived
organizationIdstring (UUID)Your organization
environmentIdstring (UUID) or nullThe environment it was created in
createdAtstring (date-time)Creation time
pricesPrice[]Active prices, on list and get only

A product is created in the environment of the key you use. Lists and lookups return the active products of that environment.

import { Moosyl } from "moosyl-sdk";

const moosyl = new Moosyl(process.env.MOOSYL_SECRET_KEY!);

const product = await moosyl.createProduct({ name: "Pro plan", description: "Everything in Pro" });
const { data: products } = await moosyl.listProducts();
const withPrices = await moosyl.getProduct(product.id);
curl -X POST https://api.moosyl.com/products \
  -H "Authorization: YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Pro plan", "description": "Everything in Pro"}'
ActionEndpointSDK
List (filter by id)GET /productslistProducts({ id?, page?, limit? })
Get, with pricesGET /products/:idgetProduct(id)
CreatePOST /productscreateProduct({ name, description? })
UpdatePATCH /products/:idupdateProduct(id, { name?, description? })
ArchivePATCH /products/:id/archivearchiveProduct(id)

Archiving sets active to false. The product then disappears from lists and lookups and can't be updated or restored. Its prices and existing subscriptions are not changed.

Prices

A price is what a subscription bills: a whole amount in MRU every week, month or year.

FieldTypeDescription
idstring (UUID)Price ID
productIdstring (UUID)The product it belongs to
amountintegerAmount in whole MRU, billed each interval
intervalweekly | monthly | yearlyHow often it bills
activebooleanfalse once archived or replaced
createdAtstring (date-time)Creation time

The SDK has no price methods yet, so use HTTP:

curl -X POST https://api.moosyl.com/prices \
  -H "Authorization: YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"productId": "PRODUCT_ID", "amount": 1000, "interval": "monthly"}'
ActionEndpointBody
GetGET /prices/:id
CreatePOST /pricesproductId, amount, interval
UpdatePATCH /prices/:idamount?, interval?, replaceExisting?
ArchivePATCH /prices/:id/archive

To list a product's prices, get the product: it includes its active prices.

Changing a price

A subscription keeps the price ID it was created with, and each renewal bills that price's current amount. Updating a price in place changes what its existing subscriptions pay from their next invoice. To leave existing subscriptions on the old amount, send replaceExisting: true: Moosyl archives the old price and returns a new price (new id) for new subscriptions.

Archiving a price hides it from lookups and from its product's price list. Subscriptions already on it keep billing.

Customers

A customer links your user to their subscriptions and invoices. Identify them with your own user ID in externalUserId.

FieldTypeDescription
idstring (UUID)Customer ID
externalUserIdstringYour user ID; unique within your organization
phonestring or nullOptional, 8-digit local number; used for their payment requests
organizationIdstring (UUID)Your organization
createdAtstring (date-time)Creation time

Customers belong to your organization, so Sandbox and Production keys see the same customers.

const customer = await moosyl.createCustomer({ externalUserId: "user_abc123", phone: "22222222" });

const { data } = await moosyl.listCustomers({ externalUserId: "user_abc123" });
curl -X POST https://api.moosyl.com/customers \
  -H "Authorization: YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"externalUserId": "user_abc123", "phone": "22222222"}'
ActionEndpointSDK
List (filter by id or externalUserId)GET /customerslistCustomers({ id?, externalUserId?, page?, limit? })
CreatePOST /customerscreateCustomer({ externalUserId, phone? })
UpdatePATCH /customers/:idupdateCustomer(id, { externalUserId?, phone? })

There's no get or delete endpoint: look a customer up with GET /customers?id=… or ?externalUserId=…. Creating a second customer with the same externalUserId fails. To create the customer and the subscription in one call, use createSubscriptionByExternalUser (see Subscriptions).

Invoices

Moosyl creates an invoice for each billing period of a subscription, with a payment request your customer pays. You can't create invoices through the API.

FieldTypeDescription
idstring (UUID)Invoice ID; also the transactionId of its payment request
customerIdstring (UUID)The customer billed
statuspending | paid | void | refundedSee below
amountstringDecimal amount in MRU, for example "1000.00"
dueDatestring (date-time) or nullDue date: the subscription's next billing date when the invoice was created
paymentRequestIdstring (UUID) or nullThe payment request to pay it
organizationIdstring (UUID)Your organization
createdAtstring (date-time)Creation time
StatusMeaning
pendingWaiting for payment
paidThe payment request was paid
voidThe subscription was cancelled while the invoice was unpaid
refundedRefunded. Not set automatically by the API today
const { data: invoices } = await moosyl.listInvoices({ subscriptionId: subscription.id });
curl "https://api.moosyl.com/invoices?subscriptionId=SUBSCRIPTION_ID" \
  -H "Authorization: YOUR_SECRET_KEY"
ActionEndpointSDK
List (filter by id, externalUserId or subscriptionId)GET /invoiceslistInvoices({ id?, externalUserId?, subscriptionId?, page?, limit? })

To collect an unpaid invoice, send your customer to its payment request, for example with a checkout session created from paymentRequestId.

Next steps

  • Subscriptions: create subscriptions and follow the billing cycle
  • Webhooks: subscription-updated and payment-request-created events
  • API reference: every parameter and response
Billing objects | Moosyl Docs