This document is designed to provide guidance to a customer migrating from Frisbii Transform to Frisbii Billing on which API’s in Frisbii Transform map to which API’s in Frisbii Billing.
Concepts of the data model, authentication, pagination and data usage is described throughout this document.
Please refer also to our API documentation for more specific details on API endpoints and responses.
Transform: https://docs.frisbii-transform.com/reference
Billing: https://docs.frisbii.com/reference
Key Differences
Engineering teams should treat this as a structural API migration rather than a simple endpoint rename.
ID format: Every entity (customer, plan, add-on, discount, coupon, subscription, invoice) moves from an integer Id to a string handle. Build a mapping table to track Transform ID → Billing handle for every entity you migrate.
Currency units: Transform amounts use decimals (e.g. 29.75). Billing uses minor currency units (e.g. 2975). Multiply by 100 when writing to Billing. This affects plans, add-ons, invoices, and refunds.
VAT/tax rate format: Transform stores VAT as an integer percentage (e.g. 19). Billing stores it as a decimal (e.g. 0.19).
Plan structure: Transform splits plan configuration across Plans[] and PlanVariants[] inside productinfo. In Billing, all settings live directly on the plan object. The PlanVariant fields (billing period, contract period, fees) need to be flattened into the Billing plan on migration.
Catalogue data: Transform returns all catalogue data (plans, add-ons, discounts, coupons) from a single GET /api/v1/productinfo endpoint. Billing exposes each resource type on its own endpoint.
Subscription creation: Transform requires a 3-step Order → Commit → Contract flow. Billing creates subscriptions in a single POST /v1/subscription call.
Payment methods: Transform embeds card info directly on the subscription (PaymentBearer). Billing treats payment methods as first-class objects. The richest card data in the Billing schema is found inside invoice.transactions[].card_transaction.
External subscriptions: The Billing response wrapper is deliberately minimal (only Id, CustomerId, Environment). Use GET /v1/subscription/{handle} to retrieve full lifecycle details.
Authentication
Transform — OAuth 2.0 Client Credentials
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic BASE64(client_id:client_secret)
Body: grant_type=client_credentials The resulting Bearer token is passed on every request, along with the legal entity header to select the tenant:
Authorization: Bearer {access_token}
X-SELECTED-LEGAL-ENTITY-ID: {legal_entity_id} Tokens expire. Implement token refresh logic (typically every 55–60 minutes).
Billing — API Key (Basic Auth)
Authorization: Basic BASE64(api_key:) The password component is always empty. The API key is per-account and does not expire.
Migration requirements:
Remove OAuth token retrieval and refresh logic
Store Billing API key securely (environment variable or secrets manager)
Remove the X-SELECTED-LEGAL-ENTITY-ID header
Update all request headers
Base URLs
Environment | Transform | Billing |
|---|---|---|
Sandbox | https://sandbox.billwerk.com/api/v1/ | https://api.frisbii.com/v1/ |
Production | https://api.billwerk.com/api/v1/ | https://api.frisbii.com/v1/ |
Note
Transform prefixes all paths with
/api/v1/.Billing uses
/v1/directly.
Pagination
This is a breaking change affecting all list operations.
Transform - Cursor-based
GET /api/v1/customers?from={lastId}&take=[pageSize}
Parameter | Description |
|---|---|
from | ID of the last record from the previous page (cursor) |
take | Number of records to return (max 500) |
The response is a flat array. When the array length is less than take, you have reached the end.
Billing - Token-based Pagination
GET /v1/list/customer?size={pageSize}&next_page_token={token}
Parameter | Description |
|---|---|
| Number of records to return per page (min 10, max 100, default 20) |
| Token returned from the previous response used to fetch the next page |
For the first request, omit next_page_token.
The response includes a next_page_token when more records are available. Use that token in the next request to continue pagination. When no next_page_token is returned, you have reached the end.
Migration
Replace cursor tracking (from) with token tracking (next_page_token).
Replace:
take→sizefrom→next_page_token
Update pagination logic:
First request: call Billing without
next_page_tokenStore the returned
next_page_tokenUse that token for the next request
Repeat until no
next_page_tokenis returned
Customers
Field Mapping
Transform Field | Billing Field | Notes |
|---|---|---|
|
| Integer → string. Define a string handle on creation; used for all subsequent references. |
|
| Direct mapping. |
|
| Billing has separate fields for invoice and dunning emails. Map from a single address if only one exists in Transform. |
|
| Direct mapping. |
|
| Direct mapping. |
|
| Direct mapping. |
|
| Renamed. |
|
| Transform may split street and house number. Concatenate into a single string for Billing. |
|
| Direct mapping. |
|
| Direct mapping. |
|
| Direct mapping. |
|
| ISO 3166-1 alpha-2 in both. |
|
| Direct mapping. |
| — | No direct field in Billing. Use the handle to carry the external ID, or store in metadata. |
|
| Direct mapping. BCP 47 language tag (e.g. |
|
| Renamed. ISO 8601 in both. |
| — | Derive from subscription state fields: |
|
| Renamed. Billing uses an integer |
— |
| Billing only. Boolean flag for test customers. |
List Customers
Transform:
GET /api/v1/customers?from={lastId}&take=100
Billing:
GET /v1/list/customer?size=100&next_page_token={token}
Get Customer
Transform:
GET /api/v1/customers/{id}
Billing:
GET /v1/customer/{handle}
Create Customer
Transform:
POST /api/v1/customers
Billing:
POST /v1/customer
Update Customer
Transform:
PUT /api/v1/customers/{id}
Billing:
PUT /v1/customer/{handle}
Product Catalogue (Plans, Add-ons, Discounts, Coupons)
Fetching Catalogue Data from Transform
All catalogue data is returned from a single endpoint:
GET /api/v1/productinfo
Response contains:
PlanGroups — groupings of plans
Plans — individual billing plans
Components — add-ons/component products
DiscountGroups — discount definitions
Coupons — coupon codes
PriceLists — pricing overrides
In Billing, these are separate resources each with their own endpoints.
Plans
Field Mapping
Transform Field | Billing Field | Notes |
|---|---|---|
|
| Integer → string handle. |
|
| Use the default locale value |
|
| Direct mapping. |
|
| Renamed. |
|
| Currency lives on PlanGroup in Transform; set directly on the plan in Billing. ISO 4217. |
|
| Net (excl. VAT) → |
|
| Renamed. Billing uses minor currency units; verify unit alignment. |
|
| Direct mapping. Minor currency units. |
|
| PostPaid → |
|
| Month → |
|
| Direct mapping. |
|
| Renamed. |
|
| Direct mapping. |
|
| Renamed. |
|
| Renamed. |
|
| Number of billing cycles. |
|
| Renamed. |
|
| Renamed. |
|
| Transform uses a single enum; Billing splits into length and unit. |
|
| Map Transform TaxPolicy ID to a Billing tax_policy handle. |
|
| Transform stores as integer (e.g. |
|
|
|
|
| If |
| — | Plan groups are not a concept in Billing. Plans are standalone. |
Transform (from productinfo):
{
"Id": 123,
"Name": "Monthly Pro",
"PlanGroupId": 10,
"Price": 4999,
"Currency": "EUR",
"BillingPeriod": "Month",
"TrialDays": 14
} Billing:
POST /v1/plan
GET /v1/plan/{handle}
GET /v1/list/plan?size=100&next_page_token={token}
Add-ons (Components)
Transform calls these Components within a ComponentSubscription on a contract.
Billing calls them Add-ons.
Field Mapping
Transform Field | Billing Field | Notes |
|---|---|---|
|
| Integer → string handle. |
|
| Direct mapping. |
— |
| Billing only. Add descriptive text when creating the add-on. |
|
| Renamed. Minor currency units in Billing. |
|
| Currency inherited from plan group in Transform; must be set explicitly on the add-on in Billing. |
|
|
|
Tax policy (inherited) |
| Set the tax policy handle explicitly in Billing. |
|
| Net → |
|
| If restricted: set |
— |
| Billing only. |
|
| Quantity is set at the subscription add-on level, not on the add-on definition. |
|
| Optional override price per subscription. |
Transform (from productinfo):
{
"Id": 55,
"Name": "Extra Storage",
"ComponentType": "PerUnit",
"Price": 500,
"Currency": "EUR"
} Billing:
Create add-on definition
POST /v1/add_on
Get
GET /v1/add_on/{handle}
List
GET /v1/list/add_on?size=100&next_page_token={token}
Fetch add-ons on a Transform contract
GET /api/v1/contracts/{contractId}/componentsubscriptions
Add add-on to a Billing subscription
Include in the subscription creation body under add_ons, or add via:
POST /v1/subscription/{handle}/add_on/{add_on_handle}
Discounts
Transform stores discounts in DiscountGroups within productinfo. Billing has independent discount objects.
Transform Field | Billing Field | Notes |
|---|---|---|
|
| Integer → string handle. |
|
| Use InternalName as the Billing |
|
| Direct mapping. |
|
| Use the |
|
| Verify percentage scale between systems. |
|
| Fixed amount in minor currency units. |
|
| Renamed. |
|
| Month → |
|
| Permanent → omit |
|
| Map target PlanVariant IDs to plan handles. Use |
| ( | Billing |
| — | Plan group scoping is not a concept in Billing. Eligibility is managed via |
— |
| Billing only. Required for fixed-amount discounts. |
— |
| Billing only. |
Transform (from productinfo)
{
"Id": 77,
"Name": "10% Loyalty",
"DiscountType": "Percentage",
"DiscountAmount": 10
} Fetch discounts applied to a contract
GET /api/v1/contracts/{contractId}/discountsubscriptions
Billing:
Create discount
POST /v1/discount
Apply discount to a subscription
POST /v1/subscription/{handle}/discount/{discount_handle}
Get
GET /v1/discount/{handle}
List
GET /v1/list/discount?size=100&next_page_token={token}
Coupons
Field Mapping
Transform Field | Billing Field | Notes |
|---|---|---|
|
| Integer → string handle. Also serves as the coupon code anchor. |
|
| Renamed. |
| — | No direct description field on the Billing coupon. Description lives on the linked discount. |
|
| Map Transform discount integer ID → Billing discount handle. |
|
| Both |
|
|
|
— |
| Billing only. Human-readable redemption code (e.g. |
— |
| Billing only. Optional cap on total uses. |
— |
| Billing only. Optional expiry datetime. |
— |
| Billing only. E.g. |
| — | Plan group scoping is not in Billing. Eligibility is managed on the linked discount. |
Transform:
GET /api/v1/coupons/{couponId}
Returns coupon with associated codes.
Billing:
Create
POST /v1/coupon
Get
GET /v1/coupon/{handle}
List
GET /v1/list/coupon?size=100&next_page_token={token}
Price Lists/Price
Transform
Transform applies price lists per Plan Group (DefaultPriceListId).
GET /api/v1/pricelists
Billing
Billing does not have price lists. Billing defines prices (amount) at plan level with the possibility to overwrite it at subscription level.
Create plan
POST /v1/plan
Overwrite price
POST /v1/subscription
Subscriptions (Contracts)
Field Mapping
Transform Field | Billing Field | Notes |
|---|---|---|
|
| Integer → string handle. |
|
| Map integer ID → customer handle. |
|
| Map Transform Plan integer ID → plan handle. |
|
| PlanVariant maps loosely to plan version. Verify billing period settings. |
|
| Direct mapping. |
|
| Renamed. |
|
| Renamed. |
|
| Direct mapping. |
|
| ISO 8601. |
|
| Direct mapping. |
|
| Renamed. |
|
| Renamed. |
|
| Not a direct equivalent. Verify against period semantics. |
|
| Renamed. |
Trial end (derived from plan) |
| Calculate from |
| — | No direct field. Check Billing credit and additional cost fields. |
|
| Direct mapping. |
|
| Transform embeds card info on the subscription. Billing references payment method objects. |
| — | PSP selection is account-level in Billing, not per subscription. |
| — | Billing has a |
|
| Derive from on_hold state + |
| — | No notes field in Billing subscription schema. Consider metadata or custom fields. |
|
| Renamed. Array of add-on handles/objects. |
|
| Renamed. Array of discount handles. |
— |
| Billing only. Coupon codes applied to the subscription. |
— |
| Billing only. Accounting cost centre. |
— |
| Billing only. Purchase order number. |
Status Mapping
Transform Status | Billing State |
|---|---|
Active | active |
Paused | on_hold |
Cancelled | cancelled |
Pending | pending |
Expired | expired |
Create Subscription
Transform flow (3 steps):
1. POST /api/v1/orders — create order
2. POST /api/v1/orders/{id}/commit — commit order
3. Contract is created automatically
Billing (1 step):
POST /v1/subscription
Get Subscription
Billing:
GET /v1/subscription/{handle}
List Subscriptions
Transform:
GET /api/v1/contracts?from={lastId}&take=100
Billing:
GET /v1/list/subscription?size=100&next_page_token={token}
Optional filters:
GET /v1/list/subscription?state=active&size=100&next_page_token={token}
Change Plan (Upgrade/Downgrade)
Transform:
Create a new order referencing the existing contract.
Billing:
POST /v1/subscription/{handle}
Lifecycle Operations
Action | Transform | Billing |
|---|---|---|
Pause | POST /api/v1/contracts/{id}/pause | POST /v1/subscription/{handle}/on_hold |
Resume | POST /api/v1/contracts/{id}/resume | POST /v1/subscription/{handle}/reactivate |
Cancel | POST /api/v1/contracts/{id}/end | POST /v1/subscription/{handle}/cancel |
Change plan | New order | POST /v1/subscription/{handle}/change |
Add discount | (via order) | POST /v1/subscription/{handle}/discount/{discount_handle} |
Invoices
Field Mapping
Transform Field | Billing Field | Notes |
|---|---|---|
|
| Transform string UUID. Billing has both |
|
| Renamed. |
|
| Map integer contract ID → subscription handle. |
|
| Map integer → customer handle. |
|
| Transform decimal → Billing minor units. Multiply × 100. |
|
| Same unit conversion applies. |
|
| Renamed. Same unit conversion applies. |
|
| Direct mapping. |
|
| ISO 8601. |
|
| Renamed. |
| — | No direct equivalent. Billing tracks |
|
| Billing |
|
| Renamed. |
| — | No separate product description on order line. Embed in |
|
| Direct mapping. |
|
| Renamed. Decimal → minor units (× 100). |
|
| Transform integer (e.g. |
|
| Renamed. Minor units in Billing. |
|
| Renamed. |
|
| Renamed. |
|
| Renamed. |
|
| Renamed. |
|
| Renamed. |
|
| Derive from |
| ( | Billing has no top-level VatDescriptors array. VAT details are per order line. |
|
| Split full name into first/last. |
|
| Concatenate: e.g. |
|
| Direct mapping. |
|
| Direct mapping. |
|
| Direct mapping. |
|
| Renamed. |
| — | Sender details are account-level in Billing; not on the invoice object. |
|
| Both use YYYY-MM-DD format. |
|
| Transform sets this at invoice level; Billing sets it per order line. |
— |
| Billing only. Dunning plan handle applied to this invoice. |
— |
| Billing only. Linked credit notes. |
Invoice States (Billing)
State | Meaning |
|---|---|
created | Draft, not yet settled |
pending | Awaiting payment |
settled | Paid |
failed | Payment failed |
cancelled | Voided |
List Invoices
Transform:
GET /api/v1/invoices?from={lastId}&take=200&dateFrom=2026-01-01&dateTo=2026-12-31
Billing:
GET v1/list/invoice?range=settled&from=2022-01-01&to=2022-02-01
Optional filters:
GET /v1/list/invoice?customer=cust-1001&state=settled&size=100
Get Invoice
Transform:
GET /api/v1/invoices/{invoiceId}
Billing:
GET /v1/invoice/{handle}
Create Manual Invoice
Transform does not support manual invoice creation; invoices are generated automatically from contracts.
Billing:
POST /v1/invoice
Orders in Transform
Orders in Transform are the mechanism for creating and modifying contracts. In Billing orders do not exists. An equivalent to “orders” would be subscription or invoice.
Transform uses orders to orchestrate all subscription changes:
Create
POST /api/v1/orders
Confirm
POST /api/v1/orders/{id}/commit
List
GET /api/v1/orders
Get Detail
GET /api/v1/orders/{id}
Charges (Payments)
Transform
Charging is implicit - handled at order commit time via PSP integration. There is no separate charge endpoint.
Billing
Explicit charge endpoint for one-off payments:
POST /v1/charge
Payment Methods
Transform embeds card info on the contract (subscription) (PaymentBearer).
Billing treats payment methods as first-class objects, and the richest card data lives inside invoice.transactions[].card_transaction.
Field Mapping
Transform Field | Billing Field | Notes |
|---|---|---|
|
| E.g. |
|
| Transform: separate integer fields. Billing: |
|
| Renamed. |
|
| Billing provides the full masked PAN (e.g. |
|
| Renamed. |
|
| Renamed. |
|
| E.g. |
|
| Transform PSP agreement ID → Billing payment_method handle. |
— |
| Billing only. Card fingerprint for deduplication. |
— |
| Billing only. 3DS / strong authentication status. |
— |
| Billing only. |
— |
| Billing only. MobilePay Online. |
— |
| Billing only. SEPA Direct Debit with IBAN and mandate reference. |
— |
| Billing only. Klarna BNPL. |
List Payment Methods
Billing:
GET /v1/list/payment_method
Set Payment Method
Transform does not have a direct payment method creation API (PSP handles this).
Billing:
POST v1/subscription/{handle}/pm
Refunds
Field Mapping
Transform Field | Billing Field | Notes |
|---|---|---|
|
| Transform uses the PSP transaction ID as identifier. Billing generates its own UUID. |
|
| Transform decimal → Billing minor units. Multiply × 100. |
| — | No requested vs. settled split in Billing. |
|
| Direct mapping. ISO 4217. |
|
| Transform: date only ( |
| — | No last-updated timestamp in the Billing refund schema. |
|
| Transform: |
— |
| Billing only. Refund must be linked to an invoice handle. |
— |
| Billing only. Original transaction ID the refund is issued against. |
— |
| Billing only. E.g. |
— |
| Billing only. Linked credit note auto-generated on refund. |
— |
| Billing only. Detailed failure info not available in the Transform refund schema. |
Transform
GET /api/v1/refunds?from={lastId}&take=100
Billing
POST /v1/refund
GET /v1/list/refund
GET /v1/refund/{id}
Dunning (Payment Escalation)
Transform:
GET /api/v1/dunnings
Billing:
Dunning plans are named resources, allowing multiple plans:
GET /v1/dunning_plan/{handle}
GET /v1/dunning_plan
PUT /v1/dunning_plan/{handle} - update
External Subscriptions
External subscriptions represent subscriptions managed outside Transform (e.g. manually billed customers). Billing has a direct equivalent.
Transform:
GET /api/v1/externalsubscriptions?from={lastId}&take=100
Billing:
The Billing response wrapper is deliberately minimal (only Id, CustomerId, Environment). Use GET /v1/subscription/{handle} to retrieve full lifecycle details.
POST /v1/subscription - with signup_method=manual
GET /v1/list/subscription?type=external
Usage/Metered Billing
Transform:
Transform usage records are tied to a contract and component.
GET /api/v1/contracts/{id}/usage
Billing:
Usage-based billing product
POST v1/metered_billing_product
Record usage
POST v1/subscription/{handle}/metered_billing_product/{metered_billing_handle}/metered_usage_record
Entitlements
Entitlements are a Billing-only concept with no direct Transform equivalent. They represent feature flags or access grants tied to a subscription.
POST /v1/entitlement
Assign to a plan to automatically grant entitlements when a customer subscribes.
Account/Validation
Both APIs provide a simple endpoint for validating credentials:
Transform | Billing | |
|---|---|---|
Validation endpoint | GET /api/v1/countrylist | GET /v1/account |
Auth check | Returns country list on success | Returns account info on success |
Error Handling
Both APIs use standard HTTP status codes.
Billing error responses have this shape:
{
"code" : 13,
"error" : "Subscription expired",
"http_reason" : "Bad Request",
"http_status" : 400,
"path" : "/v1/subscription/WHBBv/expire",
"timestamp" : "2015-06-12T06:38:33.876+0000",
"request-id" : "de03e86d0a6d44359b249340f967ddc9",
"transaction_error" : "credit_card_expired"
}HTTP code | Description |
|---|---|
| Everything worked as expected. |
| Illegal operation on a resource |
| No valid authentication provided |
| Authentication given but not authorized to resource operation |
| The requested resource or referenced resources could not be found |
| The used HTTP method is not allowed on the resource |
| The request could not be interpreted, often missing a required parameter or wrongly formatted parameters |
| The request is declined either due to request rate limiting ( |
| An internal error occurred on Frisbii Billing and Pay's end |
Handle conflicts (409): Billing uses string handles. If you generate handles from Transform IDs (e.g. "cust-1001"), you may encounter conflicts if the customer already exists. Implement upsert logic: attempt create, catch 409, fall back to update.
Migration Strategy
Phase 1: Authentication
1. Replace OAuth client credentials flow with Basic Auth API key
2. Remove token refresh logic
3. Remove X-SELECTED-LEGAL-ENTITY-ID header from all requests
4. Validate credentials against GET /v1/account
Phase 2: Identifiers
1. Change all ID storage from integer to string (handle)
2. Build a mapping table: Transform numeric ID → Billing handle
3. Persist this mapping throughout the migration — it will be referenced repeatedly
Phase 3: Catalogue Data
1. Fetch all catalogue data from Transform GET /api/v1/productinfo
2. Create Plans, Add-ons, Discounts, Coupons in Billing
3. Record ID mappings for each
Phase 4: Customers
1. List all customers from Transform with cursor pagination
2. Create in Billing using POST /v1/customer
3. Migrate payment methods per customer
Phase 5: Subscriptions
1. List all active contracts from Transform
2. Map plan, customer, add-ons, discounts, and payment method to Billing handles
3. Create subscriptions directly — no order commit step needed
4. Apply discount associations via POST /v1/subscription/{handle}/discount/{discount_handle}
Phase 6: Historical Data
1. Migrate invoices and orders for historical record
2. Migrate usage records via usage endpoint
3. Migrate refunds
Phase 7: Cutover
1. Run in parallel (both systems) with a test cohort
2. Validate data consistency
3. Re-register webhooks in Billing
4. Switch production traffic
5. Decommission Transform integration
Testing Checklist
Test Case | Expected Result |
|---|---|
Validate Transform credentials | GET /api/v1/countrylist returns country list |
Validate Billing credentials | GET /v1/account returns account object |
Fetch product catalogue | GET /api/v1/productinfo returns plans, add-ons, discounts |
Create plan in Billing | Returns plan handle |
Create add-on in Billing | Returns add-on handle |
Create discount in Billing | Returns discount handle |
Create coupon in Billing | Returns coupon handle |
Fetch Transform customers | Returns paginated list with cursor |
Create Billing customer | Returns customer handle |
Update Billing customer | Returns updated customer |
Create subscription | State = active |
Pause subscription | State = on_hold |
Resume subscription | State = active |
Cancel subscription | State = cancelled |
Change plan | Subscription reflects new plan |
Apply discount | Discount appears on subscription |
Create charge | Payment recorded |
List invoices | Returns invoice list |
Create refund | Refund recorded against invoice |
Webhook delivery | Payload received and signature verified |