Documentation Index

Fetch the complete documentation index at: https://help.frisbii.com/llms.txt

Use this file to discover all available pages before exploring further.

API Alignment Guide

Prev Next
This content is currently unavailable in German. You are viewing the default (English) version.

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

size

Number of records to return per page (min 10, max 100, default 20)

next_page_token

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:

  • takesize

  • fromnext_page_token

Update pagination logic:

  1. First request: call Billing without next_page_token

  2. Store the returned next_page_token

  3. Use that token for the next request

  4. Repeat until no next_page_token is returned


Customers

Field Mapping

Transform Field

Billing Field

Notes

Id

handle

Integer → string. Define a string handle on creation; used for all subsequent references.

EmailAddress

email

Direct mapping.

EmailAddress (single)

invoice_email / dunning_email

Billing has separate fields for invoice and dunning emails. Map from a single address if only one exists in Transform.

FirstName

first_name

Direct mapping.

LastName

last_name

Direct mapping.

Company

company

Direct mapping.

VatId

vat

Renamed.

AddressLine1 / Street + HouseNumber

address

Transform may split street and house number. Concatenate into a single string for Billing.

AddressLine2

address2

Direct mapping.

PostalCode

postal_code

Direct mapping.

City

city

Direct mapping.

Country

country

ISO 3166-1 alpha-2 in both.

Phone

phone

Direct mapping.

ExternalCustomerId

No direct field in Billing. Use the handle to carry the external ID, or store in metadata.

Language

language

Direct mapping. BCP 47 language tag (e.g. en).

CreatedDate

created

Renamed. ISO 8601 in both.

Active / Status

Derive from subscription state fields: active_subscriptions, cancelled_subscriptions, etc.

DebtorAccount

debtor_id

Renamed. Billing uses an integer debtor_id.

test

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

Plans[].Id

handle

Integer → string handle.

Plans[].Name._c

name

Use the default locale value _c.

Plans[].PlanDescription._c

description

Direct mapping.

Plans[].SetupDescription._c

setup_fee_text

Renamed.

PlanGroups[].Currency

currency

Currency lives on PlanGroup in Transform; set directly on the plan in Billing. ISO 4217.

PlanGroups[].PriceTaxType = Net

amount_incl_vat = false

Net (excl. VAT) → false. Gross → true.

PlanVariants[].RecurringFee

amount

Renamed. Billing uses minor currency units; verify unit alignment.

PlanVariants[].SetupFee

setup_fee

Direct mapping. Minor currency units.

PlanVariants[].PaymentPeriodMode = PrePaid

prepaid = true

PostPaid → prepaid: false.

PlanVariants[].BillingPeriod.Unit

schedule_type

Month → month_startdate. Year → year_startdate.

PlanVariants[].BillingPeriod.Quantity

interval_length

Direct mapping.

PlanVariants[].ContractPeriod.Unit

contract_period_unit_type

Renamed.

PlanVariants[].ContractPeriod.Quantity

contract_period

Direct mapping.

PlanVariants[].CancellationPeriod.Quantity

notice_periods

Renamed.

PlanVariants[].CancellationPeriod.Unit

notice_period_unit_type

Renamed.

PlanVariants[].FeePeriod.Quantity

fixed_count

Number of billing cycles.

PlanVariants[].AfterFirstContractPeriodNextStep = RenewAutomatically

subscription_duration_type = auto_renew

Renamed.

PlanVariants[].EndAfterFirstContractPeriod = true

subscription_duration_type = fixed

Renamed.

Plans[].TrialEndPolicy (not NoTrial)

trial_interval_length + trial_interval_unit

Transform uses a single enum; Billing splits into length and unit.

Plans[].TaxPolicyId

tax_policy

Map Transform TaxPolicy ID to a Billing tax_policy handle.

TaxPolicies[].Entries[].Rate

vat

Transform stores as integer (e.g. 19); Billing stores as decimal (e.g. 0.19).

PlanVariants[].BillingDateAlignment

schedule_fixed_day

None → no fixed day. A specific alignment → set schedule_fixed_day.

Plans[].IsQuantityBased

quantity

If true, set quantity > 1 at subscription level.

Plans[].PlanGroupId

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

Components[].Id

handle

Integer → string handle.

Components[].Name._c

name

Direct mapping.

description

Billing only. Add descriptive text when creating the add-on.

Components[].Price / RecurringFee

amount

Renamed. Minor currency units in Billing.

PlanGroups[].Currency

currency

Currency inherited from plan group in Transform; must be set explicitly on the add-on in Billing.

Components[].ComponentType = PerUnit

type = quantity

OnOffon_off.

Tax policy (inherited)

tax_policy

Set the tax policy handle explicitly in Billing.

PlanGroups[].PriceTaxType

amount_incl_vat

Net → false. Gross → true.

Components[].EligiblePlanIds

eligible_plans + all_plans

If restricted: set all_plans: false and list plan handles in eligible_plans.

state

Billing only. active / inactive; set on creation.

ComponentSubscriptions[].quantity

subscription_add_ons[].quantity

Quantity is set at the subscription add-on level, not on the add-on definition.

ComponentSubscriptions[].amount

subscription_add_ons[].amount

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

Discounts[].Id

handle

Integer → string handle.

Discounts[].InternalName

name

Use InternalName as the Billing name.

Discounts[].Description._c

description

Direct mapping.

Discounts[].Effect.Type = Relative

percentage

Use the percentage field for relative discounts.

Discounts[].Effect.ReductionPercent

percentage

Verify percentage scale between systems.

Discounts[].Effect.Type = Absolute

amount

Fixed amount in minor currency units.

Discounts[].Duration.Quantity

fixed_period

Renamed.

Discounts[].Duration.Unit

fixed_period_unit

Month → months.

Discounts[].DurationType = FixedPeriod

fixed_count (set > 0)

Permanent → omit fixed_count. FixedPeriod → set fixed_count.

Discounts[].Targets

apply_to / eligible_plans

Map target PlanVariant IDs to plan handles. Use apply_to: "all" or specify plans.

Discounts[].IncludeSetup

(apply_to logic)

Billing apply_to governs whether setup fees are included. Verify behaviour.

Discounts[].PlanGroupId

Plan group scoping is not a concept in Billing. Eligibility is managed via eligible_plans.

currency

Billing only. Required for fixed-amount discounts.

state

Billing only. active / inactive.

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

Coupons[].Id

handle

Integer → string handle. Also serves as the coupon code anchor.

Coupons[].InternalName

name

Renamed.

Coupons[].Description._c

No direct description field on the Billing coupon. Description lives on the linked discount.

Coupons[].DiscountId

discount

Map Transform discount integer ID → Billing discount handle.

Coupons[].Active / Enabled

state = active / inactive

Both Active and Enabled in Transform collapse to state in Billing.

Coupons[].IsSingleUse = true

type = single

IsSingleUse: falsetype: multi.

code

Billing only. Human-readable redemption code (e.g. FALL2024). Set explicitly.

max_redemptions

Billing only. Optional cap on total uses.

valid_until

Billing only. Optional expiry datetime.

redemption_strategy

Billing only. E.g. once_per_customer. No equivalent in Transform.

Coupons[].PlanGroupId

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

Id (Contract)

handle

Integer → string handle.

CustomerId

customer

Map integer ID → customer handle.

PlanId / CurrentPhase.PlanId

plan

Map Transform Plan integer ID → plan handle.

PlanVariantId / CurrentPhase.PlanVariantId

plan_version

PlanVariant maps loosely to plan version. Verify billing period settings.

LifecycleStatus = Active

state = active

Direct mapping.

LifecycleStatus (Paused)

state = on_hold

Renamed.

LifecycleStatus (Cancelled / Ended)

state = cancelled

Renamed.

LifecycleStatus (Expired)

state = expired

Direct mapping.

StartDate

start_date

ISO 8601.

EndDate

end_date

Direct mapping.

NextBillingDate

next_period_start

Renamed.

LastBillingDate

last_period_start

Renamed.

BilledUntil

current_period_start

Not a direct equivalent. Verify against period semantics.

Phases[Trial].StartDate

trial_start

Renamed.

Trial end (derived from plan)

trial_end

Calculate from trial_start + the plan's trial_interval.

Balance

No direct field. Check Billing credit and additional cost fields.

Currency

currency

Direct mapping.

PaymentBearer.CardType

active_payment_methods[]

Transform embeds card info on the subscription. Billing references payment method objects.

PaymentProvider

PSP selection is account-level in Billing, not per subscription.

EscalationSuspended

Billing has a dunning_plan reference. Dunning suspension is not a direct field.

RecurringPaymentsPaused

state = on_hold

Derive from on_hold state + on_hold_reason.

Notes

No notes field in Billing subscription schema. Consider metadata or custom fields.

ComponentSubscriptions

subscription_add_ons

Renamed. Array of add-on handles/objects.

DiscountSubscriptions

subscription_discounts

Renamed. Array of discount handles.

coupons

Billing only. Coupon codes applied to the subscription.

cost_center

Billing only. Accounting cost centre.

po_number

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

Id

id / handle

Transform string UUID. Billing has both id (UUID) and handle (e.g. inv-311).

InvoiceNumber

number

Renamed.

ContractId

subscription

Map integer contract ID → subscription handle.

CustomerId

customer

Map integer → customer handle.

TotalGross

amount

Transform decimal → Billing minor units. Multiply × 100.

TotalNet

amount_ex_vat

Same unit conversion applies.

TotalVat

amount_vat

Renamed. Same unit conversion applies.

Currency

currency

Direct mapping.

Created

created

ISO 8601.

DueDate

due

Renamed.

SentAt

No direct equivalent. Billing tracks settled, failed, and cancelled timestamps instead.

IsInvoice = true

type

Billing type distinguishes: subscription, additional_cost, credit_note, etc.

ItemList[].Description

order_lines[].ordertext

Renamed.

ItemList[].ProductDescription

No separate product description on order line. Embed in ordertext.

ItemList[].Quantity

order_lines[].quantity

Direct mapping.

ItemList[].PricePerUnit

order_lines[].unit_amount

Renamed. Decimal → minor units (× 100).

ItemList[].VatPercentage

order_lines[].vat

Transform integer (e.g. 19) → Billing decimal (e.g. 0.19).

ItemList[].TotalGross

order_lines[].amount

Renamed. Minor units in Billing.

ItemList[].TotalNet

order_lines[].amount_ex_vat

Renamed.

ItemList[].TotalVat

order_lines[].amount_vat

Renamed.

ItemList[].PeriodStart

order_lines[].period_from

Renamed.

ItemList[].PeriodEnd

order_lines[].period_to

Renamed.

ItemList[].DiscountId

order_lines[].discounted_order_line

Renamed.

ItemList[].IsDiscount

order_lines[].origin = discount

Derive from origin field: plan / add_on / discount.

VatDescriptors[].VatPercentage

(order_lines[].vat)

Billing has no top-level VatDescriptors array. VAT details are per order line.

RecipientName

billing_address.first_name + last_name

Split full name into first/last.

RecipientAddress.Street + HouseNumber

billing_address.address

Concatenate: e.g. "Mainzer Landstraße 33a".

RecipientAddress.PostalCode

billing_address.postal_code

Direct mapping.

RecipientAddress.City

billing_address.city

Direct mapping.

RecipientAddress.Country

billing_address.country

Direct mapping.

RecipientVatId

billing_address.vat

Renamed.

SenderName

Sender details are account-level in Billing; not on the invoice object.

DocumentDate

created (date portion)

Both use YYYY-MM-DD format.

ReverseCharge

order_lines[].applied_tax_rule = reverse_charge

Transform sets this at invoice level; Billing sets it per order line.

dunning_plan

Billing only. Dunning plan handle applied to this invoice.

credit_notes[]

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

PaymentBearer.CardType

transactions[].card_transaction.card.card_type

E.g. Visavisa_dk. Check the full type enum.

PaymentBearer.ExpiryMonth + ExpiryYear

transactions[].card_transaction.exp_date

Transform: separate integer fields. Billing: MM-YY string.

PaymentBearer.Holder

transactions[].card_transaction.cardholder_name

Renamed.

PaymentBearer.Last4

transactions[].card_transaction.masked_card

Billing provides the full masked PAN (e.g. 457111XXXXXX3777). Last 4 is the suffix.

PaymentBearer.Type = CreditCard

transactions[].payment_type = card

Renamed.

PaymentBearer.Country

transactions[].card_transaction.card.card_country

Renamed.

PaymentProvider

transactions[].card_transaction.provider

E.g. clearhaus.

AgreementId

transactions[].payment_method

Transform PSP agreement ID → Billing payment_method handle.

transactions[].card_transaction.card.fingerprint

Billing only. Card fingerprint for deduplication.

transactions[].card_transaction.strong_authentication_status

Billing only. 3DS / strong authentication status.

transactions[].card_transaction.three_d_secure_status

Billing only.

transactions[].mpo_transaction

Billing only. MobilePay Online.

transactions[].sepa_transaction

Billing only. SEPA Direct Debit with IBAN and mandate reference.

transactions[].klarna_transaction

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

pspTransactionId

id

Transform uses the PSP transaction ID as identifier. Billing generates its own UUID.

refundedAmount

amount

Transform decimal → Billing minor units. Multiply × 100.

requestedAmount

No requested vs. settled split in Billing. amount is the refunded amount.

currency

currency

Direct mapping. ISO 4217.

bookingDate

created

Transform: date only (YYYY-MM-DD). Billing: full ISO 8601 timestamp.

lastUpdated

No last-updated timestamp in the Billing refund schema.

status = Succeeded

state = refunded

Transform: Succeeded / Failed. Billing: refunded / failed / error.

invoice

Billing only. Refund must be linked to an invoice handle.

transaction

Billing only. Original transaction ID the refund is issued against.

type

Billing only. E.g. card, mobilepay.

credit_note_id

Billing only. Linked credit note auto-generated on refund.

error / error_state / acquirer_message

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

200 - OK

Everything worked as expected.

400 - Bad Request

Illegal operation on a resource

401 - Unauthorized

No valid authentication provided

403 - Forbidden

Authentication given but not authorized to resource operation

404 - Not Found

The requested resource or referenced resources could not be found

405 - Method Not Allowed

The used HTTP method is not allowed on the resource

422 - Unprocessable Entity

The request could not be interpreted, often missing a required parameter or wrongly formatted parameters

429 - Request limiting exceeded

The request is declined either due to request rate limiting (code=122) or concurrent requests limit (code=123).

500-504 - Server Errors

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