Subscription Contracts
Update billing interval for a subscription contract
Updates the billing frequency (how often the customer is charged) for a subscription contract. This comprehensive operation recalculates billing dates, adjusts pricing, updates selling plans, and may also modify delivery intervals.
Key Features:
- Changes billing frequency while maintaining subscription continuity
- Automatically adjusts delivery interval when linked to billing
- Recalculates next billing date based on store settings
- Reprices all line items for the new frequency
- Finds and applies matching selling plans
- Handles anchor day adjustments for consistent billing
- Validates prepaid subscription constraints
Billing Interval Types:
- DAY: Daily billing (use with caution)
- WEEK: Weekly billing (e.g., every 1, 2, 3 weeks)
- MONTH: Monthly billing (e.g., every 1, 2, 3 months)
- YEAR: Annual billing
Validation Rules:
- Cannot set the same interval as current (no-op prevention)
- For prepaid subscriptions: billing interval must exceed delivery interval
- Example: Can’t bill monthly if delivering weekly (would be paying for 1 delivery but receiving 4)
Next Billing Date Calculation: The system uses sophisticated logic to determine the new billing date:
- Starts from current or last successful billing date
- Applies store timezone and order time preferences
- Ensures date is in the future
- Respects day-of-week preferences if configured
- May keep current date if ‘enableChangeFromNextBillingDate’ is false
Side Effects:
- Delivery Interval: Updated if currently equal to billing interval
- Line Item Pricing: Recalculated based on new frequency multiplier
- Selling Plans: Finds and applies best matching plans for products
- Anchor Days: Updates billing anchor for consistent scheduling
- Email Notifications: Sends ‘ORDER_FREQUENCY_UPDATED’ to customer
- Activity Logs: Records both billing and delivery changes
Prepaid vs Pay-Per-Delivery:
- Pay-per-delivery: Billing and delivery intervals typically match
- Prepaid: Customer pays upfront for multiple deliveries
- This endpoint enforces prepaid logic to prevent undercharging
Authentication: Requires valid X-API-Key header
PUT
/
subscriptions
/
cp
/
api
/
subscription-contracts-update-billing-interval
Update billing interval for a subscription contract
curl --request PUT \
--url https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-intervalimport requests
url = "https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-interval"
response = requests.put(url)
print(response.text)const options = {method: 'PUT'};
fetch('https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-interval', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));const url = 'https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-interval';
const options = {method: 'PUT'};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-interval",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-interval"
req, _ := http.NewRequest("PUT", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}require 'uri'
require 'net/http'
url = URI("https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-interval")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
response = http.request(request)
puts response.read_body{
"billingPolicy": {
"anchors": [
{
"day": 1,
"type": "MONTHDAY"
}
],
"interval": "MONTH",
"intervalCount": 2
},
"customer": {
"email": "customer@example.com",
"id": "gid://shopify/Customer/987654321"
},
"deliveryPolicy": {
"interval": "MONTH",
"intervalCount": 2
},
"id": "gid://shopify/SubscriptionContract/123456789",
"lines": {
"edges": [
{
"node": {
"currentPrice": {
"amount": "59.98",
"currencyCode": "USD"
},
"id": "gid://shopify/SubscriptionLine/111111",
"pricingPolicy": {
"basePrice": {
"amount": "29.99",
"currencyCode": "USD"
}
},
"quantity": 1,
"sellingPlanId": "gid://shopify/SellingPlan/222222",
"sellingPlanName": "Deliver every 2 months",
"variantId": "gid://shopify/ProductVariant/42549172011164"
}
}
]
},
"nextBillingDate": "2024-04-01T12:00:00Z",
"status": "ACTIVE"
}Query Parameters
Available options:
DAY, WEEK, MONTH, YEAR, $UNKNOWN Response
Billing interval updated successfully
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Available options:
SUCCEEDED, FAILED, $UNKNOWN Show child attributes
Show child attributes
Show child attributes
Show child attributes
Available options:
ACTIVE, PAUSED, CANCELLED, EXPIRED, FAILED, $UNKNOWN ⌘I
Update billing interval for a subscription contract
curl --request PUT \
--url https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-intervalimport requests
url = "https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-interval"
response = requests.put(url)
print(response.text)const options = {method: 'PUT'};
fetch('https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-interval', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));const url = 'https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-interval';
const options = {method: 'PUT'};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-interval",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-interval"
req, _ := http.NewRequest("PUT", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}require 'uri'
require 'net/http'
url = URI("https://www.myshop.com/apps/subscriptions/cp/api/subscription-contracts-update-billing-interval")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
response = http.request(request)
puts response.read_body{
"billingPolicy": {
"anchors": [
{
"day": 1,
"type": "MONTHDAY"
}
],
"interval": "MONTH",
"intervalCount": 2
},
"customer": {
"email": "customer@example.com",
"id": "gid://shopify/Customer/987654321"
},
"deliveryPolicy": {
"interval": "MONTH",
"intervalCount": 2
},
"id": "gid://shopify/SubscriptionContract/123456789",
"lines": {
"edges": [
{
"node": {
"currentPrice": {
"amount": "59.98",
"currencyCode": "USD"
},
"id": "gid://shopify/SubscriptionLine/111111",
"pricingPolicy": {
"basePrice": {
"amount": "29.99",
"currencyCode": "USD"
}
},
"quantity": 1,
"sellingPlanId": "gid://shopify/SellingPlan/222222",
"sellingPlanName": "Deliver every 2 months",
"variantId": "gid://shopify/ProductVariant/42549172011164"
}
}
]
},
"nextBillingDate": "2024-04-01T12:00:00Z",
"status": "ACTIVE"
}