预览计划变更
在确认之前预览订阅计划变更的影响。返回即时收费金额和新的订阅详情,而不进行任何实际更改。
import DodoPayments from 'dodopayments';
const client = new DodoPayments({
bearerToken: process.env['DODO_PAYMENTS_API_KEY'], // This is the default and can be omitted
});
const response = await client.subscriptions.previewChangePlan('sub_Iuaq622bbmmfOGrVTqdXv', {
product_id: 'product_id',
proration_billing_mode: 'prorated_immediately',
quantity: 0,
});
console.log(response.immediate_charge);import os
from dodopayments import DodoPayments
client = DodoPayments(
bearer_token=os.environ.get("DODO_PAYMENTS_API_KEY"), # This is the default and can be omitted
)
response = client.subscriptions.preview_change_plan(
subscription_id="sub_Iuaq622bbmmfOGrVTqdXv",
product_id="product_id",
proration_billing_mode="prorated_immediately",
quantity=0,
)
print(response.immediate_charge)package main
import (
"context"
"fmt"
"github.com/dodopayments/dodopayments-go"
"github.com/dodopayments/dodopayments-go/option"
)
func main() {
client := dodopayments.NewClient(
option.WithBearerToken("My Bearer Token"),
)
response, err := client.Subscriptions.PreviewChangePlan(
context.TODO(),
"sub_Iuaq622bbmmfOGrVTqdXv",
dodopayments.SubscriptionPreviewChangePlanParams{
UpdateSubscriptionPlanReq: dodopayments.UpdateSubscriptionPlanReqParam{
ProductID: dodopayments.F("product_id"),
ProrationBillingMode: dodopayments.F(dodopayments.UpdateSubscriptionPlanReqProrationBillingModeProratedImmediately),
Quantity: dodopayments.F(int64(0)),
},
},
)
if err != nil {
panic(err.Error())
}
fmt.Printf("%+v\n", response.ImmediateCharge)
}package com.dodopayments.api.example;
import com.dodopayments.api.client.DodoPaymentsClient;
import com.dodopayments.api.client.okhttp.DodoPaymentsOkHttpClient;
import com.dodopayments.api.models.subscriptions.SubscriptionPreviewChangePlanParams;
import com.dodopayments.api.models.subscriptions.SubscriptionPreviewChangePlanResponse;
import com.dodopayments.api.models.subscriptions.UpdateSubscriptionPlanReq;
public final class Main {
private Main() {}
public static void main(String[] args) {
DodoPaymentsClient client = DodoPaymentsOkHttpClient.fromEnv();
SubscriptionPreviewChangePlanParams params = SubscriptionPreviewChangePlanParams.builder()
.subscriptionId("sub_Iuaq622bbmmfOGrVTqdXv")
.updateSubscriptionPlanReq(UpdateSubscriptionPlanReq.builder()
.productId("product_id")
.prorationBillingMode(UpdateSubscriptionPlanReq.ProrationBillingMode.PRORATED_IMMEDIATELY)
.quantity(0)
.build())
.build();
SubscriptionPreviewChangePlanResponse response = client.subscriptions().previewChangePlan(params);
}
}package com.dodopayments.api.example
import com.dodopayments.api.client.DodoPaymentsClient
import com.dodopayments.api.client.okhttp.DodoPaymentsOkHttpClient
import com.dodopayments.api.models.subscriptions.SubscriptionPreviewChangePlanParams
import com.dodopayments.api.models.subscriptions.SubscriptionPreviewChangePlanResponse
import com.dodopayments.api.models.subscriptions.UpdateSubscriptionPlanReq
fun main() {
val client: DodoPaymentsClient = DodoPaymentsOkHttpClient.fromEnv()
val params: SubscriptionPreviewChangePlanParams = SubscriptionPreviewChangePlanParams.builder()
.subscriptionId("sub_Iuaq622bbmmfOGrVTqdXv")
.updateSubscriptionPlanReq(UpdateSubscriptionPlanReq.builder()
.productId("product_id")
.prorationBillingMode(UpdateSubscriptionPlanReq.ProrationBillingMode.PRORATED_IMMEDIATELY)
.quantity(0)
.build())
.build()
val response: SubscriptionPreviewChangePlanResponse = client.subscriptions().previewChangePlan(params)
}require "dodopayments"
dodo_payments = Dodopayments::Client.new(
bearer_token: "My Bearer Token",
environment: "test_mode" # defaults to "live_mode"
)
response = dodo_payments.subscriptions.preview_change_plan(
"sub_Iuaq622bbmmfOGrVTqdXv",
product_id: "product_id",
proration_billing_mode: :prorated_immediately,
quantity: 0
)
puts(response)<?php
require_once dirname(__DIR__) . '/vendor/autoload.php';
use Dodopayments\Client;
use Dodopayments\Core\Exceptions\APIException;
$client = new Client(
bearerToken: getenv('DODO_PAYMENTS_API_KEY') ?: 'My Bearer Token',
environment: 'test_mode',
);
try {
$response = $client->subscriptions->previewChangePlan(
'sub_Iuaq622bbmmfOGrVTqdXv',
productID: 'product_id',
prorationBillingMode: 'prorated_immediately',
quantity: 0,
adaptiveCurrencyFeesInclusive: true,
addons: [['addonID' => 'addon_id', 'quantity' => 0]],
discountCode: 'discount_code',
discountCodes: ['string'],
effectiveAt: 'immediately',
metadata: ['foo' => 'string'],
onPaymentFailure: 'prevent_change',
);
var_dump($response);
} catch (APIException $e) {
echo $e->getMessage();
}using System;
using DodoPayments.Client;
using DodoPayments.Client.Models.Subscriptions;
DodoPaymentsClient client = new();
SubscriptionPreviewChangePlanParams parameters = new()
{
SubscriptionID = "sub_Iuaq622bbmmfOGrVTqdXv",
ProductID = "product_id",
ProrationBillingMode = SubscriptionPreviewChangePlanParamsProrationBillingMode.ProratedImmediately,
Quantity = 0,
};
var response = await client.Subscriptions.PreviewChangePlan(parameters);
Console.WriteLine(response);use dodopayments::Client;
#[tokio::main]
async fn main() -> dodopayments::Result<()> {
let client = Client::from_env()?;
let subscription_id = "subscription_id";
let result = client
.subscriptions()
.preview_change_plan()
.subscription_id(subscription_id)
.body(dodopayments::models::SubscriptionsChangePlanParams {
product_id: Some("product_id".to_string()),
proration_billing_mode: Some("prorated_immediately".to_string()),
quantity: Some(0),
..Default::default()
})
.await?;
println!("{result:?}");
Ok(())
}curl --request POST \
--url https://test.dodopayments.com/subscriptions/{subscription_id}/change-plan/preview \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"product_id": "<string>",
"quantity": 1,
"adaptive_currency_fees_inclusive": true,
"addons": [
{
"addon_id": "<string>",
"quantity": 1
}
],
"discount_code": "<string>",
"discount_codes": [
"<string>"
],
"metadata": {}
}
'{
"immediate_charge": {
"effective_at": "2023-11-07T05:31:56Z",
"line_items": [
{
"id": "<string>",
"product_id": "<string>",
"proration_factor": 123,
"quantity": 123,
"tax_inclusive": true,
"type": "subscription",
"unit_price": 123,
"description": "<string>",
"name": "<string>",
"tax": 123,
"tax_rate": 123
}
],
"summary": {
"customer_credits": 123,
"settlement_amount": 123,
"total_amount": 123,
"settlement_tax": 123,
"tax": 123
}
},
"new_plan": {
"addons": [
{
"addon_id": "<string>",
"quantity": 123
}
],
"billing": {
"city": "<string>",
"state": "<string>",
"street": "<string>",
"zipcode": "<string>"
},
"brand_id": "<string>",
"cancel_at_next_billing_date": true,
"created_at": "2023-11-07T05:31:56Z",
"credit_entitlement_cart": [
{
"credit_entitlement_id": "<string>",
"credit_entitlement_name": "<string>",
"credits_amount": "<string>",
"overage_balance": "<string>",
"overage_enabled": true,
"product_id": "<string>",
"remaining_balance": "<string>",
"rollover_enabled": true,
"unit": "<string>",
"expires_after_days": 123,
"low_balance_threshold_percent": 123,
"max_rollover_count": 123,
"overage_limit": "<string>",
"rollover_percentage": 123,
"rollover_timeframe_count": 123
}
],
"customer": {
"customer_id": "<string>",
"email": "<string>",
"name": "<string>",
"metadata": {},
"phone_number": "<string>"
},
"metadata": {},
"meter_credit_entitlement_cart": [
{
"credit_entitlement_id": "<string>",
"meter_id": "<string>",
"meter_name": "<string>",
"meter_units_per_credit": "<string>",
"product_id": "<string>"
}
],
"meters": [
{
"free_threshold": 123,
"measurement_unit": "<string>",
"meter_id": "<string>",
"name": "<string>",
"description": "<string>",
"price_per_unit": "10.50"
}
],
"next_billing_date": "2023-11-07T05:31:56Z",
"on_demand": true,
"payment_frequency_count": 123,
"previous_billing_date": "2023-11-07T05:31:56Z",
"product_id": "<string>",
"quantity": 123,
"recurring_pre_tax_amount": 123,
"subscription_id": "<string>",
"subscription_period_count": 123,
"tax_inclusive": true,
"trial_period_days": 123,
"cancellation_comment": "<string>",
"cancelled_at": "2023-11-07T05:31:56Z",
"custom_field_responses": [
{
"key": "<string>",
"value": "<string>"
}
],
"customer_business_name": "<string>",
"discount_cycles_remaining": 123,
"discount_id": "<string>",
"discounts": [
{
"amount": 123,
"business_id": "<string>",
"code": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"discount_id": "<string>",
"metadata": {},
"position": 123,
"preserve_on_plan_change": true,
"restricted_to": [
"<string>"
],
"times_used": 123,
"type": "percentage",
"cycles_remaining": 123,
"expires_at": "2023-11-07T05:31:56Z",
"name": "<string>",
"subscription_cycles": 123,
"usage_limit": 123
}
],
"expires_at": "2023-11-07T05:31:56Z",
"payment_method_id": "<string>",
"scheduled_change": {
"addons": [
{
"addon_id": "<string>",
"name": "<string>",
"quantity": 123
}
],
"created_at": "2023-11-07T05:31:56Z",
"effective_at": "2023-11-07T05:31:56Z",
"id": "<string>",
"product_id": "<string>",
"quantity": 123,
"product_description": "<string>",
"product_name": "<string>"
},
"tax_id": "<string>"
}
}用例
- 结账确认:在客户确认更改计划前显示按比例分配的费用
- 价格计算器:在您的应用程序中构建升级/降级计算器
- 客户自助服务:让客户以准确的价格探索计划选项
- 折扣验证:预览累加的折扣代码如何影响计划更改的定价
discount_codes(最多20个代码的数组,按顺序应用)以查看累加折扣如何在提交更改前影响即时费用和新计划定价。单个 discount_code 字段已弃用,但仍支持向后兼容;我们建议继续使用 discount_codes。响应字段
预览响应包括:| 字段 | 描述 |
|---|---|
immediate_charge | 将立即创建的费用,包括各项和摘要 |
new_plan | 显示更改计划后的完整订阅对象 |
immediate_charge.summary 包含将收取的总金额。在客户确认计划更改之前使用此信息显示定价。授权
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
路径参数
Subscription Id
请求体
Unique identifier of the product to subscribe to
Proration Billing Mode
prorated_immediately, full_immediately, difference_immediately, do_not_bill Number of units to subscribe for. Must be at least 1.
x >= 0Whether adaptive currency fees should be included in the price (true) or added on top (false). If not specified, uses the subscription's stored setting.
Addons for the new plan. Note : Leaving this empty would remove any existing addons
Show child attributes
Show child attributes
DEPRECATED: Use discount_codes instead. Cannot be used together with discount_codes.
Stacked discount codes to apply to the new plan. Max 20. Cannot be used together with discount_code. If provided, replaces any existing discount codes. Empty array removes all discounts. If not provided (None), existing discounts with preserve_on_plan_change=true are preserved.
When to apply the plan change.
immediately(default): Apply the plan change right awaynext_billing_date: Schedule the change for the next billing date
immediately, next_billing_date Metadata for the payment. If not passed, the metadata of the subscription will be taken
Show child attributes
Show child attributes
Controls behavior when the plan change payment fails.
prevent_change: Keep subscription on current plan until payment succeedsapply_change(default): Apply plan change immediately regardless of payment outcome
If not specified, uses the business-level default setting.
prevent_change, apply_change import DodoPayments from 'dodopayments';
const client = new DodoPayments({
bearerToken: process.env['DODO_PAYMENTS_API_KEY'], // This is the default and can be omitted
});
const response = await client.subscriptions.previewChangePlan('sub_Iuaq622bbmmfOGrVTqdXv', {
product_id: 'product_id',
proration_billing_mode: 'prorated_immediately',
quantity: 0,
});
console.log(response.immediate_charge);import os
from dodopayments import DodoPayments
client = DodoPayments(
bearer_token=os.environ.get("DODO_PAYMENTS_API_KEY"), # This is the default and can be omitted
)
response = client.subscriptions.preview_change_plan(
subscription_id="sub_Iuaq622bbmmfOGrVTqdXv",
product_id="product_id",
proration_billing_mode="prorated_immediately",
quantity=0,
)
print(response.immediate_charge)package main
import (
"context"
"fmt"
"github.com/dodopayments/dodopayments-go"
"github.com/dodopayments/dodopayments-go/option"
)
func main() {
client := dodopayments.NewClient(
option.WithBearerToken("My Bearer Token"),
)
response, err := client.Subscriptions.PreviewChangePlan(
context.TODO(),
"sub_Iuaq622bbmmfOGrVTqdXv",
dodopayments.SubscriptionPreviewChangePlanParams{
UpdateSubscriptionPlanReq: dodopayments.UpdateSubscriptionPlanReqParam{
ProductID: dodopayments.F("product_id"),
ProrationBillingMode: dodopayments.F(dodopayments.UpdateSubscriptionPlanReqProrationBillingModeProratedImmediately),
Quantity: dodopayments.F(int64(0)),
},
},
)
if err != nil {
panic(err.Error())
}
fmt.Printf("%+v\n", response.ImmediateCharge)
}package com.dodopayments.api.example;
import com.dodopayments.api.client.DodoPaymentsClient;
import com.dodopayments.api.client.okhttp.DodoPaymentsOkHttpClient;
import com.dodopayments.api.models.subscriptions.SubscriptionPreviewChangePlanParams;
import com.dodopayments.api.models.subscriptions.SubscriptionPreviewChangePlanResponse;
import com.dodopayments.api.models.subscriptions.UpdateSubscriptionPlanReq;
public final class Main {
private Main() {}
public static void main(String[] args) {
DodoPaymentsClient client = DodoPaymentsOkHttpClient.fromEnv();
SubscriptionPreviewChangePlanParams params = SubscriptionPreviewChangePlanParams.builder()
.subscriptionId("sub_Iuaq622bbmmfOGrVTqdXv")
.updateSubscriptionPlanReq(UpdateSubscriptionPlanReq.builder()
.productId("product_id")
.prorationBillingMode(UpdateSubscriptionPlanReq.ProrationBillingMode.PRORATED_IMMEDIATELY)
.quantity(0)
.build())
.build();
SubscriptionPreviewChangePlanResponse response = client.subscriptions().previewChangePlan(params);
}
}package com.dodopayments.api.example
import com.dodopayments.api.client.DodoPaymentsClient
import com.dodopayments.api.client.okhttp.DodoPaymentsOkHttpClient
import com.dodopayments.api.models.subscriptions.SubscriptionPreviewChangePlanParams
import com.dodopayments.api.models.subscriptions.SubscriptionPreviewChangePlanResponse
import com.dodopayments.api.models.subscriptions.UpdateSubscriptionPlanReq
fun main() {
val client: DodoPaymentsClient = DodoPaymentsOkHttpClient.fromEnv()
val params: SubscriptionPreviewChangePlanParams = SubscriptionPreviewChangePlanParams.builder()
.subscriptionId("sub_Iuaq622bbmmfOGrVTqdXv")
.updateSubscriptionPlanReq(UpdateSubscriptionPlanReq.builder()
.productId("product_id")
.prorationBillingMode(UpdateSubscriptionPlanReq.ProrationBillingMode.PRORATED_IMMEDIATELY)
.quantity(0)
.build())
.build()
val response: SubscriptionPreviewChangePlanResponse = client.subscriptions().previewChangePlan(params)
}require "dodopayments"
dodo_payments = Dodopayments::Client.new(
bearer_token: "My Bearer Token",
environment: "test_mode" # defaults to "live_mode"
)
response = dodo_payments.subscriptions.preview_change_plan(
"sub_Iuaq622bbmmfOGrVTqdXv",
product_id: "product_id",
proration_billing_mode: :prorated_immediately,
quantity: 0
)
puts(response)<?php
require_once dirname(__DIR__) . '/vendor/autoload.php';
use Dodopayments\Client;
use Dodopayments\Core\Exceptions\APIException;
$client = new Client(
bearerToken: getenv('DODO_PAYMENTS_API_KEY') ?: 'My Bearer Token',
environment: 'test_mode',
);
try {
$response = $client->subscriptions->previewChangePlan(
'sub_Iuaq622bbmmfOGrVTqdXv',
productID: 'product_id',
prorationBillingMode: 'prorated_immediately',
quantity: 0,
adaptiveCurrencyFeesInclusive: true,
addons: [['addonID' => 'addon_id', 'quantity' => 0]],
discountCode: 'discount_code',
discountCodes: ['string'],
effectiveAt: 'immediately',
metadata: ['foo' => 'string'],
onPaymentFailure: 'prevent_change',
);
var_dump($response);
} catch (APIException $e) {
echo $e->getMessage();
}using System;
using DodoPayments.Client;
using DodoPayments.Client.Models.Subscriptions;
DodoPaymentsClient client = new();
SubscriptionPreviewChangePlanParams parameters = new()
{
SubscriptionID = "sub_Iuaq622bbmmfOGrVTqdXv",
ProductID = "product_id",
ProrationBillingMode = SubscriptionPreviewChangePlanParamsProrationBillingMode.ProratedImmediately,
Quantity = 0,
};
var response = await client.Subscriptions.PreviewChangePlan(parameters);
Console.WriteLine(response);use dodopayments::Client;
#[tokio::main]
async fn main() -> dodopayments::Result<()> {
let client = Client::from_env()?;
let subscription_id = "subscription_id";
let result = client
.subscriptions()
.preview_change_plan()
.subscription_id(subscription_id)
.body(dodopayments::models::SubscriptionsChangePlanParams {
product_id: Some("product_id".to_string()),
proration_billing_mode: Some("prorated_immediately".to_string()),
quantity: Some(0),
..Default::default()
})
.await?;
println!("{result:?}");
Ok(())
}curl --request POST \
--url https://test.dodopayments.com/subscriptions/{subscription_id}/change-plan/preview \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"product_id": "<string>",
"quantity": 1,
"adaptive_currency_fees_inclusive": true,
"addons": [
{
"addon_id": "<string>",
"quantity": 1
}
],
"discount_code": "<string>",
"discount_codes": [
"<string>"
],
"metadata": {}
}
'{
"immediate_charge": {
"effective_at": "2023-11-07T05:31:56Z",
"line_items": [
{
"id": "<string>",
"product_id": "<string>",
"proration_factor": 123,
"quantity": 123,
"tax_inclusive": true,
"type": "subscription",
"unit_price": 123,
"description": "<string>",
"name": "<string>",
"tax": 123,
"tax_rate": 123
}
],
"summary": {
"customer_credits": 123,
"settlement_amount": 123,
"total_amount": 123,
"settlement_tax": 123,
"tax": 123
}
},
"new_plan": {
"addons": [
{
"addon_id": "<string>",
"quantity": 123
}
],
"billing": {
"city": "<string>",
"state": "<string>",
"street": "<string>",
"zipcode": "<string>"
},
"brand_id": "<string>",
"cancel_at_next_billing_date": true,
"created_at": "2023-11-07T05:31:56Z",
"credit_entitlement_cart": [
{
"credit_entitlement_id": "<string>",
"credit_entitlement_name": "<string>",
"credits_amount": "<string>",
"overage_balance": "<string>",
"overage_enabled": true,
"product_id": "<string>",
"remaining_balance": "<string>",
"rollover_enabled": true,
"unit": "<string>",
"expires_after_days": 123,
"low_balance_threshold_percent": 123,
"max_rollover_count": 123,
"overage_limit": "<string>",
"rollover_percentage": 123,
"rollover_timeframe_count": 123
}
],
"customer": {
"customer_id": "<string>",
"email": "<string>",
"name": "<string>",
"metadata": {},
"phone_number": "<string>"
},
"metadata": {},
"meter_credit_entitlement_cart": [
{
"credit_entitlement_id": "<string>",
"meter_id": "<string>",
"meter_name": "<string>",
"meter_units_per_credit": "<string>",
"product_id": "<string>"
}
],
"meters": [
{
"free_threshold": 123,
"measurement_unit": "<string>",
"meter_id": "<string>",
"name": "<string>",
"description": "<string>",
"price_per_unit": "10.50"
}
],
"next_billing_date": "2023-11-07T05:31:56Z",
"on_demand": true,
"payment_frequency_count": 123,
"previous_billing_date": "2023-11-07T05:31:56Z",
"product_id": "<string>",
"quantity": 123,
"recurring_pre_tax_amount": 123,
"subscription_id": "<string>",
"subscription_period_count": 123,
"tax_inclusive": true,
"trial_period_days": 123,
"cancellation_comment": "<string>",
"cancelled_at": "2023-11-07T05:31:56Z",
"custom_field_responses": [
{
"key": "<string>",
"value": "<string>"
}
],
"customer_business_name": "<string>",
"discount_cycles_remaining": 123,
"discount_id": "<string>",
"discounts": [
{
"amount": 123,
"business_id": "<string>",
"code": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"discount_id": "<string>",
"metadata": {},
"position": 123,
"preserve_on_plan_change": true,
"restricted_to": [
"<string>"
],
"times_used": 123,
"type": "percentage",
"cycles_remaining": 123,
"expires_at": "2023-11-07T05:31:56Z",
"name": "<string>",
"subscription_cycles": 123,
"usage_limit": 123
}
],
"expires_at": "2023-11-07T05:31:56Z",
"payment_method_id": "<string>",
"scheduled_change": {
"addons": [
{
"addon_id": "<string>",
"name": "<string>",
"quantity": 123
}
],
"created_at": "2023-11-07T05:31:56Z",
"effective_at": "2023-11-07T05:31:56Z",
"id": "<string>",
"product_id": "<string>",
"quantity": 123,
"product_description": "<string>",
"product_name": "<string>"
},
"tax_id": "<string>"
}
}