INTRODUCTION

Many common actions require modifying resources in a particular way, obeying a number of contraints. We've collected a few use cases for common scenarios here.


CONTRACTS

Adding contract for new customer

For simple signup/subscription implementation we recommend using BillwerkJS rather than API, unless you have strong reasons.

Sample Request
POST /Orders
{
  "TriggerInterimBilling": false,
  "Cart": {
    "PlanVariantId": "5c19763aba5c1e0854af481a",
    "InheritStartDate": false,
    "ComponentSubscriptions": [
      {
        "ComponentId": "5c19763aba5c1e0854af4818",
        "Quantity": 2.0
      }
    ]
  },
  "Customer": {
    "CompanyName": "ACME Inc.",
    "FirstName": "John",
    "LastName": "Doe",
    "VatId": "DE424324234",
    "EmailAddress": "john.doe@example.com",
    "Address": {
      "AddressLine1": "c/o Coworking Ltd.",
      "Street": "Zschopauer Straße",
      "HouseNumber": "42",
      "PostalCode": "10123",
      "City": "Berlin",
      "Country": "DE"
    },
    "Hidden": false
  },
  "PreviewAfterTrial": false
}

Remove ComponentSubscriptions or pass empty array if no components are subscribed.

Sample Response
{
  "Id": "5c19763aba5c1e0854af4829",
  "AllowWithoutPaymentData": true,
  "ComponentSubscriptions": [
    {
      "ComponentType": "QuantityBased",
      "PreventModification": false,
      "VatPercentage": 19.0,
      "TotalNet": 2.0,
      "TotalVat": 0.38,
      "IsQuantityBased": false,
      "ComponentId": "5c19763aba5c1e0854af4818",
      "Quantity": 2.0
    }
  ],
  "Total": 7.0,
  "TotalVat": 1.33,
  "TotalGross": 0.0,
  "NextTotalGross": 0.0,
  "IsTrial": false,
  "TrialEndPolicy": "NoTrial",
  "Status": "InProgress",
  "OrderType": "Signup",
  "TriggerInterimBilling": false,
  "CustomerId": "5c19763aba5c1e0854af482a",
  "ContractId": "5c19763aba5c1e0854af47ff",
  "PreviewAfterTrial": false
}

Adding contract to existing customer

To create a second contract for a customer requires a somewhat different process than creating a new customer altogether, because we have no way of identifying, authenticating or authorizing your customers. Hence, to create a second contract for an existing customer, the request must go through your server's backend to the REST API. However, that separation makes sense because the workflow is quite different from an end-user perspective, usually. Re-entering a lot of information seems useless, and the order process usually doesn't involve the public web site's checkout process.

Create order

Sample Request
POST /Orders
{
  "TriggerInterimBilling": false,
  "CustomerId": "5c19763aba5c1e0854af482a",
  "Cart": {
    "PlanVariantId": "5c19763aba5c1e0854af481a",
    "InheritStartDate": false,
    "ComponentSubscriptions": [
      {
        "ComponentId": "5c19763aba5c1e0854af4818",
        "Quantity": 2.0
      }
    ]
  },
  "PreviewAfterTrial": false
}
Sample Response
{
  "Id": "5c19763aba5c1e0854af482b",
  "AllowWithoutPaymentData": true,
  "ComponentSubscriptions": [
    {
      "ComponentType": "QuantityBased",
      "PreventModification": false,
      "VatPercentage": 19.0,
      "TotalNet": 2.0,
      "TotalVat": 0.38,
      "IsQuantityBased": false,
      "ComponentId": "5c19763aba5c1e0854af4818",
      "Quantity": 2.0
    }
  ],
  "Total": 7.0,
  "TotalVat": 1.33,
  "TotalGross": 0.0,
  "NextTotalGross": 0.0,
  "IsTrial": false,
  "TrialEndPolicy": "NoTrial",
  "Status": "InProgress",
  "OrderType": "Signup",
  "TriggerInterimBilling": false,
  "CustomerId": "5c19763aba5c1e0854af482c",
  "ContractId": "5c19763aba5c1e0854af47ff",
  "PreviewAfterTrial": false
}

Commit the order through a payment

The details depend on your payment requirements. If the customer only pays on account or you let him signup without payment data you can also use an API call. In the more common use case where you need to (or at least want to have the option to) collect payment data again, we're facing the interactive payment process implemented in BillwerkJS again.

BillwerkJS offers a method paySignupInteractive(billwerkJSPayment, secretPaymentData, order, success, error) that you can use to perform the interactive payment of an order. This method is internally called by BillwerkJS's subscribe(), too. However, subscribe() also creates the order via JS. In other words, creating orders is one of the few processes that can be performed both via JS and via the REST API.


Up-/Downgrading to a plan

Sample Request
POST /Orders
{
  "TriggerInterimBilling": false,
  "ContractId": "5c19763aba5c1e0854af47ff",
  "Cart": {
    "PlanVariantId": "5c19763aba5c1e0854af481b",
    "InheritStartDate": false,
    "ComponentSubscriptions": [
      {
        "ComponentId": "5c19763aba5c1e0854af4818",
        "Quantity": 2.0
      }
    ],
    "MeteredUsages": [
      {
        "ComponentId": "5c19763aba5c1e0854af481e",
        "Quantity": 3.0,
        "Memo": "Memo text",
        "Key": "Some unique external key 12345",
        "DueDate": "2018-12-17T22:35:38.3911954Z"
      }
    ],
    "EndComponentSubscriptions": [
      "5c19763aba5c1e0854af481c",
      "5c19763aba5c1e0854af481d"
    ]
  },
  "PreviewAfterTrial": false
}

By default up-/downgrade orders are processed instantly after commit with POST /Orders/:OrderId/commit.

An up-/downgrade of a plan will change all future billing times. Billing periods will be calculated based on the up-/downgrade time.

With an up-/downgrade you can also add/remove component subscriptions and pass metered usage. Omit ComponentSubscriptions, EndComponentSubscriptions, MeteredUsages or pass empty array if not used.

Sample Response
{
  "Id": "5c19763aba5c1e0854af482b",
  "AllowWithoutPaymentData": true,
  "ComponentSubscriptions": [
    {
      "ComponentType": "QuantityBased",
      "PreventModification": false,
      "VatPercentage": 19.0,
      "TotalNet": 2.0,
      "TotalVat": 0.38,
      "IsQuantityBased": false,
      "ComponentId": "5c19763aba5c1e0854af4818",
      "Quantity": 2.0
    }
  ],
  "Total": 7.0,
  "TotalVat": 1.33,
  "TotalGross": 0.0,
  "NextTotalGross": 0.0,
  "IsTrial": false,
  "TrialEndPolicy": "NoTrial",
  "Status": "InProgress",
  "OrderType": "Signup",
  "TriggerInterimBilling": false,
  "CustomerId": "5c19763aba5c1e0854af482c",
  "ContractId": "5c19763aba5c1e0854af47ff",
  "PreviewAfterTrial": false
}

Terminate a Contract (with notice)

To terminate a contract and have billwerk honor the notice period, you need to query a cancellation preview, then proceed as in the case of an irregular cancellation, i.e.:

Sample Request
GET /contracts/:contractId/cancellationPreview
{
  "NextPossibleCancellationDate": "2018-02-07T23:00:00Z",
  "EndDate": "2018-02-08T23:00:00Z", //You'll want to post this EndDate later
  "Invoice": {...},
  "ContractAfter": {...}
}
POST /contracts/:contractId/end
{
  "EndDate": "2018-02-08T23:00:00Z"
}

Terminate a Contract (not honoring the notice period)

Sample Request

POST /contracts/:contractId/end
{
  "EndDate": "2018-02-08T23:00:00Z"
}

The EndDate must satisfy two contraints:
  • It must be greater than the contract's StartDate, i.e. you can't currently 'delete' a contract that hasn't started yet.
  • It must lie in the future.

COMPONENT SUBSCRIPTIONS

Adding/Removing component subscriptions only

Sample Request
POST /Orders
{
  "TriggerInterimBilling": false,
  "ContractId": "5c19763aba5c1e0854af47ff",
  "Cart": {
    "InheritStartDate": false,
    "ComponentSubscriptions": [
      {
        "ComponentId": "5c19763aba5c1e0854af4818",
        "Quantity": 2.0
      }
    ],
    "EndComponentSubscriptions": [
      "5c19763aba5c1e0854af481f",
      "5c19763aba5c1e0854af4820"
    ]
  },
  "PreviewAfterTrial": false
}

If you simply want to add/remove component subscriptions and keep the current plan variant you can do so by omitting the planVariantId. Creating an order this way will keep future billing times. An instant intermediate billing will be done instead.

Remove ComponentSubscriptions, EndComponentSubscriptions from the sample request as required.

Sample Response
{
  "Id": "5c19763aba5c1e0854af482b",
  "AllowWithoutPaymentData": true,
  "ComponentSubscriptions": [
    {
      "ComponentType": "QuantityBased",
      "PreventModification": false,
      "VatPercentage": 19.0,
      "TotalNet": 2.0,
      "TotalVat": 0.38,
      "IsQuantityBased": false,
      "ComponentId": "5c19763aba5c1e0854af4818",
      "Quantity": 2.0
    }
  ],
  "Total": 7.0,
  "TotalVat": 1.33,
  "TotalGross": 0.0,
  "NextTotalGross": 0.0,
  "IsTrial": false,
  "TrialEndPolicy": "NoTrial",
  "Status": "InProgress",
  "OrderType": "Signup",
  "TriggerInterimBilling": false,
  "CustomerId": "5c19763aba5c1e0854af482c",
  "ContractId": "5c19763aba5c1e0854af47ff",
  "PreviewAfterTrial": false
}

In-/Decreasing quantity

Sample Request
POST /Orders
{
  "TriggerInterimBilling": false,
  "ContractId": "5c19763aba5c1e0854af47ff",
  "Cart": {
    "InheritStartDate": false,
    "ComponentSubscriptions": [
      {
        "ComponentId": "5c19763aba5c1e0854af4818",
        "Quantity": 4.0
      }
    ],
    "EndComponentSubscriptions": [
      "5c19763aba5c1e0854af4818"
    ]
  },
  "PreviewAfterTrial": false
}

If you simply want to change the quantity of a subscribed component, there is a shortcut. Subscribe to a component with the new quantity. In EndComponentSubscription pass the component id instead of listing component subscription ids. All corresponding subscriptions will be finished. The new subscription will be the only existing one for the component.

Sample Response
{
  "Id": "5c19763aba5c1e0854af482d",
  "AllowWithoutPaymentData": true,
  "ComponentSubscriptions": [
    {
      "ComponentType": "QuantityBased",
      "PreventModification": false,
      "VatPercentage": 19.0,
      "TotalNet": 4.0,
      "TotalVat": 0.76,
      "IsQuantityBased": false,
      "ComponentId": "5c19763aba5c1e0854af4818",
      "Quantity": 4.0
    }
  ],
  "Total": 7.0,
  "TotalVat": 1.33,
  "TotalGross": 0.0,
  "NextTotalGross": 0.0,
  "IsTrial": false,
  "TrialEndPolicy": "NoTrial",
  "Status": "InProgress",
  "OrderType": "Signup",
  "TriggerInterimBilling": false,
  "CustomerId": "5c19763aba5c1e0854af482e",
  "ContractId": "5c19763aba5c1e0854af47ff",
  "PreviewAfterTrial": false
}

DISCOUNTS

Adding discounts

Adding discounts to an order is equivalent to adding a component. It can be applied to signup and up-/downgrade orders. Specifying a start date is optional.

Sample Request (direct discount)
POST /Orders
{
  "TriggerInterimBilling": false,
  "ContractId": "5c19763aba5c1e0854af47ff",
  "Cart": {
    "InheritStartDate": false,
    "DiscountSubscriptions": [
      {
        "StartDate": "2018-12-20T22:35:38.3911954Z",
        "DiscountId": "5c19763aba5c1e0854af4819"
      }
    ]
  },
  "PreviewAfterTrial": false
}

The example shows adding a discount to an upgrade order

Sample Response
{
  "Id": "5c19763aba5c1e0854af4831",
  "AllowWithoutPaymentData": false,
  "Total": 10.0,
  "TotalVat": 1.9,
  "TotalGross": 0.0,
  "NextTotalGross": 0.0,
  "IsTrial": false,
  "TrialEndPolicy": "NoTrial",
  "Status": "InProgress",
  "OrderType": "Signup",
  "TriggerInterimBilling": false,
  "CustomerId": "5c19763aba5c1e0854af4832",
  "ContractId": "5c19763aba5c1e0854af47ff",
  "PreviewAfterTrial": false
}

Adding discounts via coupon is only available in signup orders. The discount the coupon code is assigned to will be applied.

The example shows adding a discount to an upgrade order

Sample Response
{
  "Id": "5c19763aba5c1e0854af4831",
  "AllowWithoutPaymentData": false,
  "Total": 10.0,
  "TotalVat": 1.9,
  "TotalGross": 0.0,
  "NextTotalGross": 0.0,
  "IsTrial": false,
  "TrialEndPolicy": "NoTrial",
  "Status": "InProgress",
  "OrderType": "Signup",
  "TriggerInterimBilling": false,
  "CustomerId": "5c19763aba5c1e0854af4832",
  "ContractId": "5c19763aba5c1e0854af47ff",
  "PreviewAfterTrial": false
}

Adding discounts via coupon

Sample Request
POST /Orders
{
  "TriggerInterimBilling": false,
  "Cart": {
    "PlanVariantId": "5c19763aba5c1e0854af4822",
    "InheritStartDate": false,
    "CouponCode": "ABCDEF"
  },
  "Customer": {
    "CompanyName": "ACME Inc.",
    "FirstName": "John",
    "LastName": "Doe",
    "VatId": "DE424324234",
    "EmailAddress": "john.doe@example.com",
    "Address": {
      "AddressLine1": "c/o Coworking Ltd.",
      "Street": "Zschopauer Straße",
      "HouseNumber": "42",
      "PostalCode": "10123",
      "City": "Berlin",
      "Country": "DE"
    },
    "Hidden": false
  },
  "PreviewAfterTrial": false
}

MISCELLANEOUS

Processing an order in the future

By default orders are processed instantly after the commit. Orders for existing contracts can also be processed in the future by passing the ChangeDate

Sample Request
POST /Orders
{
  "ChangeDate": "2019-01-07T22:35:38.3941204Z",
  "TriggerInterimBilling": false,
  "ContractId": "5c19763aba5c1e0854af47ff",
  "Cart": {
    "PlanVariantId": "5c19763aba5c1e0854af4821",
    "InheritStartDate": false
  },
  "PreviewAfterTrial": false
}
Sample Response
{
  "Id": "5c19763aba5c1e0854af482f",
  "AllowWithoutPaymentData": false,
  "Total": 10.0,
  "TotalVat": 1.9,
  "TotalGross": 0.0,
  "NextTotalGross": 0.0,
  "IsTrial": false,
  "TrialEndPolicy": "NoTrial",
  "Status": "InProgress",
  "OrderType": "Signup",
  "TriggerInterimBilling": false,
  "CustomerId": "5c19763aba5c1e0854af4830",
  "ContractId": "5c19763aba5c1e0854af47ff",
  "PreviewAfterTrial": false
}

Bill metered usage

Metered usage will be billed even from previous billing periods, so you can simply post it with the correct DueDate, even if far in the past. However, it is unclear how this is supposed to interact with free quota.