Octany. for/devs OpenAPI
§ 04 — API reference

Browse the API by resource.

The Octany API manages subscriptions, products, orders, and webhook endpoints. Use this page when you want to understand the human shape of the API. Use the OpenAPI spec when you need machine-readable types.

Base contract Every endpoint is scoped to one account: https://api.octany.com/api/{account}. Send your per-account API key in X-API-KEY.

§ 04.1 Basics #

Base URL

https://api.octany.com/api/{account}

Authentication

X-API-KEY: <your-api-key>
X-Locale: en

API keys are scoped to a single account. Set X-Locale if you want translated validation messages and formatted strings in a specific language.

Resource IDs

Subscription, order, and webhook-delivery id values are integers in production today (e.g. 76963688). Treat them as opaque identifiers in your storage layer — store them in a column wide enough to fit a future format change (a string column, or bigint). Don't validate the format and don't gate on is_int / typeof === 'number'; just round-trip them as you received them. Product IDs are integers and unlikely to change. Account IDs are UUIDs.

Pagination

List endpoints return data plus pagination. Use ?page=2 to move through results. Send X-Locale: en if you want English error/validation messages.

{
  "data": [],
  "pagination": {
    "total": 142,
    "count": 20,
    "per_page": 20,
    "current_page": 1,
    "total_pages": 8,
    "links": { "next": "https://api.octany.com/api/{account}/subscriptions?page=2" }
  }
}

§ 04.2 Subscriptions #

Subscriptions represent recurring billing for one product. Store the subscription id after subscription.created arrives, then use it for cancellation, one-off orders, or product changes.

GET/subscriptions

List subscriptions. Supports page and filter[reference_id].

curl "https://api.octany.com/api/$ACCOUNT/subscriptions?filter[reference_id]=user_42" \
  -H "X-API-KEY: $OCTANY_KEY"
GET/subscription/{id}

Retrieve one subscription by its Octany subscription ID.

curl "https://api.octany.com/api/$ACCOUNT/subscription/76963688" \
  -H "X-API-KEY: $OCTANY_KEY"
POST/subscription/{id}/cancel

Cancel a subscription. No further renewals will be attempted. Depending on the product, the subscription may remain active until ends_at.

curl -X POST "https://api.octany.com/api/$ACCOUNT/subscription/76963688/cancel" \
  -H "X-API-KEY: $OCTANY_KEY"
POST/subscription/{id}/product

Swap the product on a subscription.

curl -X POST "https://api.octany.com/api/$ACCOUNT/subscription/76963688/product" \
  -H "X-API-KEY: $OCTANY_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "product_id": 42 }'
GET/subscription/{id}/orders

List orders for a subscription. Supports page, per_page, filter[product_id], and filter[state].

curl "https://api.octany.com/api/$ACCOUNT/subscription/76963688/orders?filter[state]=paid&per_page=50" \
  -H "X-API-KEY: $OCTANY_KEY"
POST/subscription/{id}/order

Create a one-off order on an existing subscription, billed through the subscription's billing method.

curl -X POST "https://api.octany.com/api/$ACCOUNT/subscription/76963688/order" \
  -H "X-API-KEY: $OCTANY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "product_id": 89,
        "amount": 4995,
        "quantity": 1,
        "vat": 2500,
        "description": "Extra item"
      }'

§ 04.3 Orders #

GET/order/{id}

Retrieve an order by its Octany order ID. Orders expose totals, VAT, state, reference fields, delivery links, metadata, and custom fields.

curl "https://api.octany.com/api/$ACCOUNT/order/516253755" \
  -H "X-API-KEY: $OCTANY_KEY"

Order states

created confirmed payment_pending_user payment_pending payment_failed payment_cancelled payment_refunded paid

§ 04.4 Products #

GET/products

List products. Product responses include pricing, VAT, interval, stock flags, images, and display strings.

curl "https://api.octany.com/api/$ACCOUNT/products" \
  -H "X-API-KEY: $OCTANY_KEY"
GET/product/{id}

Retrieve one product by numeric product ID.

curl "https://api.octany.com/api/$ACCOUNT/product/42" \
  -H "X-API-KEY: $OCTANY_KEY"
POST/product/{id}

Update a product. Only sent fields are updated.

curl -X POST "https://api.octany.com/api/$ACCOUNT/product/42" \
  -H "X-API-KEY: $OCTANY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Monthly membership",
        "description": "Access to member content.",
        "price": 9900,
        "currency": "SEK",
        "vat_rate": 25,
        "interval": "month"
      }'
DELETE/product/{id}

Delete a product.

curl -X DELETE "https://api.octany.com/api/$ACCOUNT/product/42" \
  -H "X-API-KEY: $OCTANY_KEY"

§ 04.5 Webhook endpoints #

POST/webhooks/endpoints

Register a URL to receive signed webhook events. The endpoint secret is generated by Octany and read from the admin UI after creation.

curl -X POST "https://api.octany.com/api/$ACCOUNT/webhooks/endpoints" \
  -H "X-API-KEY: $OCTANY_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://app.example.com/octany/webhook" }'

§ 04.6 Payload shapes #

Subscription status lifecycle

Eight values: pending, future_start, trialing, active, delayed, unpaid, cancelled, expired. Two transitions trip up integrators:

The single boolean integrators usually want:

function isPaying(string $status, ?DateTimeInterface $endsAt): bool
{
    return in_array($status, ['active', 'trialing'], true)
        && ($endsAt === null || $endsAt > new DateTime());
}

Anything else — delayed, unpaid, pending, expired, cancelled past ends_at — is "no entitlement." See integration.md for the full lifecycle diagram.

Subscription

{
  "id": 76963688,
  "price": 9900,
  "vat": 2500,
  "currency": "SEK",
  "renews_at": "2026-05-25T09:29:51+00:00",
  "reference_id": "member_42",
  "reference_name": "Anna Persson",
  "status": "active",
  "update_card_url": "https://octanybilling.com/...",
  "invoices_url": "https://octanybilling.com/...",
  "cancel_url": "https://octanybilling.com/...",
  "custom_fields": [],
  "metadata": {}
}

Order

{
  "id": 516253755,
  "total": 7920,
  "total_with_vat": 9900,
  "currency": "SEK",
  "reference_id": "member_42",
  "state": "paid",
  "delivery": { "link": "https://..." },
  "custom_fields": [],
  "metadata": {}
}

Product

{
  "id": 42,
  "name": "Monthly membership",
  "description": "Access to member content.",
  "type": "Recurring",
  "price": 9900,
  "price_with_vat": 9900,
  "price_without_vat": 7920,
  "currency": "SEK",
  "vat_rate": 25,
  "interval": "month",
  "use_cart": true,
  "stock_tracking": false,
  "out_of_stock": false
}